文档
自定义对话框

自定义 Dialog

概述

对话框(Dialog)用于渲染 Say 模式下的角色对话,包括角色名牌和文本内容。通过 game.configure 替换默认的 Dialog 组件,即可实现完全自定义的对话框样式。

本文档演示如何创建自定义对话框,并配合 NametagTexts 调整名牌和文本的展示。

1. 创建自定义 Dialog 组件

使用 DialogNametagTexts 三个子组件构建布局。Dialog 为容器,Nametag 渲染角色名,Texts 渲染对话文本。

import { Dialog, Nametag, Texts } from "narraleaf-react";
 
function GameDialog() {
  return (
    <Dialog
      className="bg-black/70 rounded-lg px-6 py-4"
      // Dialog: container for the dialog box, supports className/style
    >
      <Nametag className="text-lg font-bold text-amber-400" />
      {/* Nametag: character name, color is defined in character config */}
      <Texts className="text-white text-base leading-relaxed" />
      {/* Texts: dialogue content, inherits from word/sentence config */}
    </Dialog>
  );
}

2. 使用 useDialog 获取状态(可选)

若需在子组件中读取当前对话状态(如 donetextisNarrator),可使用 useDialog Hook:

import { Dialog, Nametag, Texts, useDialog } from "narraleaf-react";
 
function GameDialog() {
  const { done, text, isNarrator } = useDialog();
  // done: whether typing is complete
  // text: current displayed text
  // isNarrator: true when speaker is null (narrator)
 
  return (
    <Dialog className="bg-black/70 rounded-lg px-6 py-4">
      {!isNarrator && <Nametag className="text-lg font-bold" />}
      {/* Hide nametag when narrator speaks */}
      <Texts className="text-white" />
    </Dialog>
  );
}

3. 在 App 中注册

通过 useGame 获取游戏实例,在 useEffect 中调用 game.configure 注册自定义组件:

import { useEffect } from "react";
import { useGame, Player } from "narraleaf-react";
import GameDialog from "./GameDialog";
 
function App() {
  const game = useGame();
 
  useEffect(() => {
    game.configure({
      dialog: GameDialog,  // Replace default dialog with custom one
    });
  }, [game]);
 
  return (
    <Player>
      {/* ... */}
    </Player>
  );
}

4. 完整示例(参考 narraleaf-react-skeleton (opens in a new tab)

以下示例展示:使用 useDialogdone 控制打字完成指示器,isNarrator 控制名牌显隐,以及背景图样式:

import { Dialog, Nametag, Texts, useDialog } from "narraleaf-react";
import clsx from "clsx";
 
// Sub-component: show triangle/underline when typing is done
function SentenceContext() {
  const { done } = useDialog();
  return (
    <>
      <Texts className="text-[22px] max-w-max flex items-center" />
      <div className="flex flex-col items-center">
        <div className={clsx(
          "w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-t-[10px] border-t-white",
          done ? "opacity-100" : "opacity-0"  // Show indicator when done
        )} />
        <div className="w-[12px] h-[2px] bg-white mt-[2px]" />
      </div>
    </>
  );
}
 
export function GameDialog() {
  const { isNarrator } = useDialog();
 
  return (
    <Dialog
      className="absolute bottom-4 left-1/2 -translate-x-1/2 p-12 px-16 w-[90%] h-[216px]"
      style={{
        backgroundImage: "url('/ui/game-dialog.png')",
        backgroundSize: "contain",
        backgroundPosition: "bottom",
        backgroundRepeat: "no-repeat",
      }}
    >
      <div className={clsx("absolute left-[30px] -top-[15px]", { "hidden": isNarrator })}>
        <Nametag
          className="px-4 py-2 min-w-[220px] min-h-[56px] flex items-center justify-center"
          style={{
            backgroundImage: "url('/ui/game-dialog-nametag.png')",
            backgroundSize: "contain",
            backgroundPosition: "center",
            backgroundRepeat: "no-repeat",
          }}
        />
      </div>
      <div className="flex items-center gap-[5px] h-full">
        <SentenceContext />
      </div>
    </Dialog>
  );
}

注册时还可设置 defaultTextColordefaultNametagColor 等默认颜色:

game.configure({
  dialog: GameDialog,
  defaultTextColor: "white",
  defaultNametagColor: "#2987a1",
});

5. 简单样式示例

function GameDialog() {
  return (
    <Dialog
      style={{
        backgroundColor: "rgba(0, 0, 0, 0.6)",
        borderRadius: "12px",
        padding: "24px",
        border: "1px solid rgba(255, 255, 255, 0.2)",
      }}
    >
      <Nametag style={{ marginBottom: "8px", paddingBottom: "4px", borderBottom: "2px solid rgba(255, 193, 7, 0.8)" }} />
      <Texts />
    </Dialog>
  );
}

注意事项

  • 名牌颜色:由 Character 配置中的 nametagColor 控制,不建议用 CSS 覆盖。
  • 文本样式:由 Word / Sentence 配置控制,可自定义背景、字体、大小等未预定义属性。