- SpeciesId 从 10 项联合类型改为 string,动态从 @pkmn/sim Dex 加载 1025 只精灵 - getSpecies() 改用 Dex.species.get() 直接查找(gen wrapper 仅覆盖 733/1025) - SUPPLEMENT/DEX_TO_SPECIES 动态生成,未收录 species 使用默认值兜底 - names/fallback 改为 partial records,缺失时回退到 Dex 英文名/通用 sprite - 新增 SpeciesPicker 组件(基于 FuzzyPicker),支持中英文/编号搜索选择精灵 - BattleFlow configSelect 阶段替换为 SpeciesPicker,删除旧的上下翻页逻辑 - evolution 移除 ALL_SPECIES_IDS 限制,所有 Dex 物种均可进化 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
import React, { useState, useMemo, useCallback } from 'react'
|
|
import { Box, Text, FuzzyPicker } from '@anthropic/ink'
|
|
import type { SpeciesId } from '../types'
|
|
import { ALL_SPECIES_IDS } from '../types'
|
|
import { getSpeciesData } from '../dex/species'
|
|
|
|
/** Pre-computed species entry for picker */
|
|
type SpeciesEntry = {
|
|
id: SpeciesId
|
|
name: string
|
|
displayName: string // zh name or English name
|
|
dexNumber: number
|
|
types: string[]
|
|
}
|
|
|
|
// Build all entries once (species data is cached internally by getSpeciesData)
|
|
const ALL_ENTRIES: SpeciesEntry[] = ALL_SPECIES_IDS.map(id => {
|
|
const data = getSpeciesData(id)
|
|
return {
|
|
id,
|
|
name: data.name,
|
|
displayName: (data.names as Record<string, string>).zh ?? data.name,
|
|
dexNumber: data.dexNumber,
|
|
types: data.types as string[],
|
|
}
|
|
})
|
|
|
|
/** Searchable species picker using FuzzyPicker */
|
|
export function SpeciesPicker({
|
|
onSelect,
|
|
onCancel,
|
|
title = '选择精灵',
|
|
}: {
|
|
onSelect: (speciesId: SpeciesId) => void
|
|
onCancel: () => void
|
|
title?: string
|
|
}) {
|
|
const [filtered, setFiltered] = useState<SpeciesEntry[]>(ALL_ENTRIES.slice(0, 50))
|
|
|
|
const handleQueryChange = useCallback((q: string) => {
|
|
if (!q.trim()) {
|
|
setFiltered(ALL_ENTRIES.slice(0, 50))
|
|
return
|
|
}
|
|
const lower = q.toLowerCase()
|
|
const matched = ALL_ENTRIES.filter(e =>
|
|
e.id.includes(lower) ||
|
|
e.name.toLowerCase().includes(lower) ||
|
|
e.displayName.includes(q) ||
|
|
String(e.dexNumber).includes(q)
|
|
)
|
|
setFiltered(matched.slice(0, 100))
|
|
}, [])
|
|
|
|
return (
|
|
<FuzzyPicker<SpeciesEntry>
|
|
title={title}
|
|
placeholder="输入名称或编号搜索…"
|
|
items={filtered}
|
|
getKey={item => item.id}
|
|
renderItem={(item, focused) => (
|
|
<Box>
|
|
<Text color={focused ? 'claude' : undefined} bold={focused}>
|
|
#{String(item.dexNumber).padStart(3, '0')} {item.displayName}
|
|
</Text>
|
|
{item.displayName !== item.name && (
|
|
<Text dimColor> {item.name}</Text>
|
|
)}
|
|
<Text color="inactive"> {item.types.join('/')}</Text>
|
|
</Box>
|
|
)}
|
|
onQueryChange={handleQueryChange}
|
|
onSelect={item => onSelect(item.id)}
|
|
onCancel={onCancel}
|
|
emptyMessage={q => `没有找到 "${q}" 相关的精灵`}
|
|
matchLabel={filtered.length < ALL_ENTRIES.length ? `${filtered.length} 个结果` : undefined}
|
|
/>
|
|
)
|
|
}
|