itsjavi / storylite

[Experimental] Lightweight alternative to StoryBook for React, built on top of Vite⚡️, compatible with CSF 3.0
http://itsjavi.com/storylite/
MIT License
112 stars 0 forks source link

[bug]: localStorageKey option has no effect #49

Open itsjavi opened 1 year ago

itsjavi commented 1 year ago

Describe the bug

When setting the localStorageKey, to a different value than the default, the UI options are not persisted and the default key is still used in the local storage.

Reproduction

  1. Set it in the story lite config:
const config: Partial<SLAppComponentProps> = {
  localStorageKey: 'my-custom-key',
}
  1. Launch the UI, try to change something in the toolbar and refresh the page. The toolbar option is reset.
jrson83 commented 1 year ago

I tried to replicate with react-example. When refresh page with F5, the toolbar option is reset, but the localStorage key and also addon state is as expected. So either it tries to load the default key storylite, which does not exist, or something else is wrong.

  1. In config.tsx I set localStorageKey: 'storylite-react',.
  2. In index.html and canvas.html I changed the key:

const slParams = window.localStorage.getItem('storylite-react.parameters')

  1. Load App
  2. Clear localStorage
  3. Refresh Page
  4. Check localStorage: Is Empty
  5. Toggle outline addon
  6. The localStorage key is storylite-react. The localStorage value is:
{
  "grid": {
    "value": false
  },
  "responsive": {
    "value": false
  },
  "outline": {
    "value": true
  },
  "maximize": {
    "value": false
  },
  "theme": {
    "value": "auto"
  }
}
  1. Refresh page. The addon in ui is disabled, when checking localStorage key is storylite-react, it still has the outline set to true.
jrson83 commented 1 year ago

I tried to fix the issue, but there are multiple approaches.

Use zustand build in persisting store data

Docs: I got it working wrapping useStoryLiteStore like this:

import { createJSONStorage, persist } from 'zustand/middleware'
import { shallow } from 'zustand/shallow'
import { createWithEqualityFn } from 'zustand/traditional'

export const useStoryLiteStore = createWithEqualityFn<StoryLiteStore>()(
  persist(
    set => {
      const createStoryMap = (moduleMap: StoryModuleMap): StoryMap => {
        ...
      }

      return {
        ...defaultState,
        ...
      }
    },
    {
      name: 'storylite.parameters',
      partialize: state => state.parameters,
      storage: createJSONStorage(() => localStorage),
    },
  ),
  shallow,
)

The Object stored in localStorage will be wrapped with state looks like this:

{
  "state": {
    "grid": {
      "value": false
    },
    "responsive": {
      "value": false
    },
    "outline": {
      "value": false
    },
    "maximize": {
      "value": false
    },
    "theme": {
      "value": "auto"
    }
  },
  "version": 0
}

When using this approach, the custom setParameter and setParameters function must be refactored.

In addition initalize state with props

Like described in the Docs, I think this would be easiest way to implement.

Split state into multiple objects

For me it makes sense to split state into multiple objects, only apply persistant to the parameters and then create one merged store maybe.


There might be more approaches, but I think to use the build in zustand localStorage makes sense and maybe speeds up things. I tried but I find the zustand docs very complicated and they do not have examples for multiple combined recipes like using createWithEqualityFn with persistent & shallow. This search helped a lot to understand.

Would be great if you take care on the issue and hope this info helps. I better get into the SCSS 😁

itsjavi commented 1 year ago

Thank you for the investigation @jrson83 . We can also have multiple stores, let's see... and maybe it's time for me to add proper tests :D

I will take care of this