Storybook a Zustand

Hledám nějaké rozumné řešení prezentace komponent ve Storybooku, které jsou navržené pro práci s Zustandem (nebo jiným global state managementem). Vycházím z předpokladu, že v design-systemu by měly být komponenty v rámci svých možností co nejvíc agnostické.

Momentální řešení: Inicializuji separate store v rámci každé story, který obsahuje nezbytné minimum pro funkčnost komponenty.

Teď otázka zda řešit toto, jelikož momentálníé řešení nění úplně aligned s filozofií SB.

Store instance je pro celý modul**, a tu pak všechny stories sdílejí (riziko “prosakování” stavu mezi jednotlivými stories [Default, Second])

Existuje robustnějiši řešní (Decorator Mocking nebo Context Provider), které by overbleed stavu mělo vyřešit a vypadá to, že decorators jsou lepší cesta, abych nemusel přepisovat komponentu.

// FilterForm.stories.tsx

import type { Meta, StoryObj } from '@storybook/react';

import { FilterForm } from '@repo/design-system/components';
import { create } from 'zustand'; // Import create from zustand

const meta: Meta<typeof FilterForm> = {
  title: 'Components/FilterForm',
  component: FilterForm,
  tags: ['autodocs'],
};

type FilterFormStory = StoryObj<typeof meta>;

const useStoryStore = create((set) => ({
  items: [
    { value: 'one', label: 'One', checked: false },
    { value: 'two', label: 'Two', checked: false }, // Example initial state
    { value: 'three', label: 'Three', checked: false },
  ],
  toggleItems: (value) =>
    set((state) => ({
      items: state.items.map((item) => (item.value === value ? { ...item, checked: !item.checked } : item)),
    })),
  toggleAllItems: () =>
    set((state) => ({
      items: state.items.map((item) => ({ ...item, checked: !item.checked })),
    })),
}));

export const Default: FilterFormStory = {
  render: () => {
    const items = useStoryStore((state) => state.items);
    const toggleItem = useStoryStore((state) => state.toggleItems);
    const toggleAllItems = useStoryStore((state) => state.toggleAllItems);

    console.log(items);

    return (
      <div>
        <FilterForm items={items} toggleItem={(value) => toggleItem(value)} toggleAllItems={toggleAllItems} />
      </div>
    );
  },
};

export default meta;

Co myslíte?

Storybook (a v zasade jakakoli aplikace, ktera pouziva ten design-system by nemel znat tolik implementacnich detailu. e.g. nevytvaris ve Storybooku samotne store.

Ty si musis z design-system vyexportovat Provider, ktery tohle vsechno obhospodari. Kdyz k tomu pridas i dobry default state, tak potom tam kde to pouzijes (treba ten Storybook) zavolas jenom napriklad

<KalkulackaProvider>{children}</KalkulackaProvider>

a bude to vsecko propojene.

1 Like