import { useEffect, useState, type KeyboardEvent as ReactKeyboardEvent } from "react"; import { type ProjectDialogue } from "../dialogues/project-dialogues"; interface NpcDialoguesPanelProps { dialogues: ProjectDialogue[]; defaultDialogueId: string | null; selectedDialogueId: string | null; onSelectDialogue(dialogueId: string | null): void; onSetDefaultDialogueId(dialogueId: string | null): void; onAddDialogue(): void; onDeleteDialogue(dialogueId: string): void; onSetDialogueTitle(dialogueId: string, title: string): void; onAddDialogueLine(dialogueId: string): void; onDeleteDialogueLine(dialogueId: string, lineId: string): void; onSetDialogueLineText(dialogueId: string, lineId: string, text: string): void; } function commitOnEnter( event: ReactKeyboardEvent, commit: () => void ) { if (event.key !== "Enter") { return; } event.currentTarget.blur(); commit(); } export function NpcDialoguesPanel({ dialogues, defaultDialogueId, selectedDialogueId, onSelectDialogue, onSetDefaultDialogueId, onAddDialogue, onDeleteDialogue, onSetDialogueTitle, onAddDialogueLine, onDeleteDialogueLine, onSetDialogueLineText }: NpcDialoguesPanelProps) { const selectedDialogue = selectedDialogueId === null ? null : dialogues.find((dialogue) => dialogue.id === selectedDialogueId) ?? null; const resolvedDefaultDialogueId = defaultDialogueId !== null && dialogues.some((dialogue) => dialogue.id === defaultDialogueId) ? defaultDialogueId : null; const defaultDialogue = resolvedDefaultDialogueId === null ? null : dialogues.find((dialogue) => dialogue.id === resolvedDefaultDialogueId) ?? null; const [titleDraft, setTitleDraft] = useState(selectedDialogue?.title ?? ""); const [lineDrafts, setLineDrafts] = useState>( {} ); useEffect(() => { setTitleDraft(selectedDialogue?.title ?? ""); setLineDrafts( selectedDialogue === null ? {} : Object.fromEntries( selectedDialogue.lines.map((line) => [ line.id, { text: line.text } ]) ) ); }, [selectedDialogueId, selectedDialogue]); const commitTitle = () => { if (selectedDialogue === null) { return; } onSetDialogueTitle(selectedDialogue.id, titleDraft); }; const getLineDraft = (dialogue: ProjectDialogue, lineId: string) => lineDrafts[lineId] ?? (() => { const line = dialogue.lines.find((candidate) => candidate.id === lineId); return { text: line?.text ?? "" }; })(); return (
{defaultDialogue?.title ?? (dialogues.length === 0 ? "No Dialogues" : "No Default Dialogue")}
{dialogues.length === 0 ? "Author one or more dialogues for this NPC. NPC sequence links can later make this NPC talk." : defaultDialogue === null ? "Pick a default dialogue for NPC talk effects that do not target a specific dialogue." : `${defaultDialogue.lines.length} line${defaultDialogue.lines.length === 1 ? "" : "s"} in the default NPC dialogue.`}
Dialogues
{dialogues.length === 0 ? (
No NPC dialogues authored yet.
) : (
{dialogues.map((dialogue) => (
))}
)}
{selectedDialogue === null ? (
Select a dialogue to edit its title and lines.
) : (
Lines
{selectedDialogue.lines.map((line, index) => { const draft = getLineDraft(selectedDialogue, line.id); return (
{`Line ${index + 1}`}