跳至內容
Fumadocs

無頭式

替換 stories 的 UI,或基於無頭式層自行建構 UI。

概覽

@fumadocs/story 匯出了 <StoryProvider />、useStory() 與 useStoryArgs(),可在不含 UI 的情況下提供元件情境的狀態:

  • 所選的變體,以及其對應的預設組合
  • 已渲染元件的引數,並經過防抖 (debounce) 處理,因此輸入時不會每按一個鍵就重新算繪元件

內建面板就是以這些 API 建構而成,您也可以改用自己實作的面板。

自訂面板

defineStoryFactory() 可接受一個 WithControl 元件,並以它取代內建面板進行算繪。

lib/story.tsx
import { defineStoryFactory } from '@fumadocs/story/vite/client';
import { StoryPanel } from '@/components/story-panel';

export const { defineStory } = defineStoryFactory({ WithControl: StoryPanel });

此元件會接收元件情境的預設組合,以及要算繪的元件。

components/story-panel.tsx
'use client';
import { StoryProvider, useStory, useStoryArgs, type WithControlProps } from '@fumadocs/story';

export function StoryPanel(props: WithControlProps) {
  return (
    <StoryProvider {...props}>
      <Content />
    </StoryProvider>
  );
}

function Content() {
  const { presets, variant, setVariant, preset, Component } = useStory();
  const args = useStoryArgs();

  return (
    <div>
      <select value={variant} onChange={(e) => setVariant(e.target.value)}>
        {presets.map((item) => (
          <option key={item.variant} value={item.variant}>
            {item.variant}
          </option>
        ))}
      </select>
      <Component {...args} />
      <pre>{JSON.stringify(preset?.controls, null, 2)}</pre>
    </div>
  );
}
Hook說明
useStory()預設組合、目前選取的 variant 與 setVariant,以及 Component 和 frame。
useStoryArgs()已渲染元件的引數,會隨控制項同步更新。
useStoryFrame()frame 的 iframe 所用的 ref,負責將引數傳送給該 iframe。

控制項透過 @fumari/stf 編輯,也就是 <StoryProvider /> 所設定的表單引擎。preset.controls 是元件 props 的型別樹。

從內建面板開始

要撰寫完整的控制面板,就必須處理型別樹中的每一種節點。建議您安裝下方的內建 面板,再加以修改。

安裝 UI

整個面板,包括其中的引數控制項:

npx @fumadocs/cli add story/controls
lib/story.tsx
import { defineStoryFactory } from '@fumadocs/story/vite/client';
import { WithControl } from '@/components/story';

export const { defineStory } = defineStoryFactory({ WithControl });

How is this guide?

最後更新於