/** * 通用模态表单(plan.md 管理页 CRUD)。 * * 底部弹出的模态对话框,包含多个文本输入字段 + 确认/取消按钮。 * 供分类/标签/预算/信用卡/规则管理页的「添加/编辑」复用。 * * 用法: * { /* 保存 *\/ }} * onCancel={() => { /* 关闭 *\/ }} * /> */ import React, { useEffect, useState } from 'react'; import { Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native'; import { useTheme } from '../theme'; import { useT } from '../i18n'; import { Button } from './Button'; export interface FormField { /** 字段 key,对应 values 对象的属性名。 */ key: string; /** 显示标签。 */ label: string; /** 占位提示。 */ placeholder?: string; /** 默认值(新增时为空,编辑时预填)。 */ defaultValue?: string; /** 键盘类型。 */ keyboardType?: 'default' | 'numeric' | 'decimal-pad' | 'phone-pad'; /** 多行输入。 */ multiline?: boolean; } interface FormModalProps { visible: boolean; title: string; fields: FormField[]; onConfirm: (values: Record) => void; onCancel: () => void; /** 确认按钮文本(默认「确定」)。 */ confirmLabel?: string; } export function FormModal({ visible, title, fields, onConfirm, onCancel, confirmLabel }: FormModalProps) { const { theme } = useTheme(); const t = useT(); const [values, setValues] = useState>({}); // 每次 visible 变为 true 时,用 fields 的 defaultValue 初始化 useEffect(() => { if (visible) { const init: Record = {}; for (const f of fields) { init[f.key] = f.defaultValue ?? ''; } setValues(init); } }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps return ( e.stopPropagation()} > {title} {fields.map(f => ( {f.label} setValues(prev => ({ ...prev, [f.key]: text }))} placeholder={f.placeholder} placeholderTextColor={theme.colors.fgSecondary} keyboardType={f.keyboardType ?? 'default'} multiline={f.multiline} style={[styles.input, { backgroundColor: theme.colors.bgTertiary, color: theme.colors.fgPrimary, borderColor: theme.colors.border, borderRadius: theme.radii.sm, }]} /> ))}