AI 應用元件

同步打字網格

多格同步打字展示 React 元件:同一句提示詞在 N 個不同外殼的輸入框裡同時逐字打出,內建對話框、終端機、搜尋列、文件編輯器四種外殼,適合比較多個介面或展示「到哪都能用」。

把同一句提示詞同時打進 2–6 個不同外觀的輸入框:所有格子共用一個打字時鐘,逐字同步出現;打完後可以讓每格淡入一段假結果,再清空重打或輪播下一句。內建 chat、terminal、search、editor 四種外殼,也能用 render 傳入自己的殼。適合產品首頁說明「同一個功能在對話、指令列、搜尋、編輯器裡都能用」,或並排比較多個介面的回應格式。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add synced-typing-grid

還沒有專案,或安裝遇到問題?看快速開始 →

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

55
0
2
編輯中的呼叫預設屬性
<SyncedTypingGrid/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add https://webberui.com/r/synced-typing-grid.json

或在 components.json 設定 registries 後,改用 @webberui/synced-typing-grid 安裝。

使用

import { SyncedTypingGrid } from "@/components/ui/synced-typing-grid";

<SyncedTypingGrid
  text="幫我把上週的客訴整理成三點摘要"
  columns={2}
  jitter={40}
  cells={[
    { id: "chat", label: "對話助理", variant: "chat", result: <p>已整理成三點摘要</p> },
    { id: "terminal", label: "指令列", variant: "terminal" },
    { id: "search", label: "站內搜尋", variant: "search" },
    {
      id: "custom",
      label: "自訂外殼",
      render: (typed, done) => (
        <div className="rounded-lg border p-3 text-sm">
          {typed}
          {done ? " ✓" : null}
        </div>
      ),
    },
  ]}
/>

Props

Prop型別預設值說明
textstring | string[]—要同步打出的句子;傳陣列時依序輪播多句
cellsSyncedTypingCell[]—各格的介面設定(建議 2–6 格)
typeSpeednumber55每個字的間隔(毫秒)
startDelaynumber300每句開始打字前的等待(毫秒)
pauseDurationnumber1800打完後停留多久再進入下一句或重打(毫秒)
loopbooleantrue是否循環播放;false 時播完最後一句就停住
jitternumber0每格確定性的時間偏移上限(±毫秒),製造「幾乎同步」的錯落感;0 為完全同步
columnsnumber2大螢幕(lg 以上)的欄數,1–6;手機固定 1 欄、sm 為 2 欄
playingboolean—受控播放狀態;未提供時由元件內部管理
defaultPlayingbooleantrue非受控模式的初始播放狀態
onPlayingChange(playing: boolean) => void—播放狀態變動時回呼
onDone(sentenceIndex: number) => void—每句全部格子打完時回呼,參數為句子索引
showControlsbooleantrue是否顯示播放/暫停按鈕
labelstring"同步打字展示"根元素的無障礙名稱
pauseLabelstring"暫停"暫停按鈕文字
playLabelstring"播放"播放按鈕文字
replayLabelstring"重播"播完後的重播按鈕文字
classNamestring—透傳到最外層容器

SyncedTypingCell

欄位型別預設值說明
idstring—唯一識別碼,作為 React key
labelstring—格子頂部顯示的介面名稱
variant"chat" | "terminal" | "search" | "editor""chat"內建外殼樣式;傳了 render 時忽略
render(typed: string, done: boolean) => ReactNode—自訂外殼:取得目前已打出的字串與是否打完,回傳任意節點
resultReactNode—整句打完後淡入的結果節點(例如假回應)

細節

  • 單一共享時鐘:一個計時器推進共用的經過時間,每格據此算出該顯示幾個字,所以所有格子逐字同步;jitter 大於 0 時,每格依索引雜湊得到固定的時間偏移(不用亂數),SSR 與瀏覽器算出的值一致,每次重打的節奏也一樣。
  • 切字用 Array.from,以 code point 為單位,中文與 emoji 不會被切成亂碼。
  • 傳入陣列時依序輪播;loop 為 false 時播完最後一句停住,按鈕會變成「重播」。
  • 暫停後再播放會從原本的位置接續,不會從頭開始。
  • 節奏可用 CSS 變數覆寫:--wb-synced-typing-caret(游標閃爍週期,預設 1s)、--wb-synced-typing-result-duration(結果淡入時長,預設 320ms);送出鈕與狀態點的顏色轉換沿用 --wb-duration-fast 與 --wb-ease-out。

可及性

  • 根元素為 role="group",以 label 作為無障礙名稱
  • 逐字打字的區域設定 aria-hidden,另放一段 sr-only 的完整句子,螢幕閱讀器不會逐字播報
  • 播放/暫停按鈕為原生 button,文字隨狀態切換(暫停/播放/重播),可用鍵盤操作並有 focus-visible 外框
  • 元件不在視口內時(IntersectionObserver)自動暫停,捲回畫面後接續
  • 使用者系統開啟「減少動態效果」時,直接顯示完整句子與結果,不打字、游標不閃爍,也不顯示播放按鈕