import { useLayoutEffect, useRef, useState } from 'react' import { Form } from '@react-spectrum/s2/Form' import { Button, ButtonGroup } from '@react-spectrum/s2/ButtonGroup' import { Picker, PickerItem } from '@react-spectrum/s2/Picker' import { Switch } from '@react-spectrum/s2/Switch' import { Checkbox } from '@react-spectrum/s2/Checkbox' import TextFields from './text-fields' import SelectionFields from './selection-fields' import DateNumberFields from './date-number-fields' import ColorFileFields from './color-file-fields' import styles from './form-examples.module.css' function DemoForm({ onReset }: { onReset: () => void }) { const containerRef = useRef(null) const [isCompact, setIsCompact] = useState(false) const [size, setSize] = useState<'S' | 'M' | 'L' | 'XL'>('M') const [sideLabels, setSideLabels] = useState(false) const [disabled, setDisabled] = useState(false) const [errors, setErrors] = useState>({}) const [result, setResult] = useState | null>(null) useLayoutEffect(() => { const container = containerRef.current if (!container) return const update = () => setIsCompact(container.clientWidth < 560) update() const observer = new ResizeObserver(update) observer.observe(container) return () => observer.disconnect() }, []) const useSideLabels = sideLabels && !isCompact return (
{ if (key === 'S' || key === 'M' || key === 'L' || key === 'XL') setSize(key) }}> SMLXL 标签放在侧边 禁用表单
{sideLabels && isCompact &&

当前宽度较窄,已自动使用顶部标签。

}
{ event.preventDefault(); onReset() }} onSubmit={(event) => { event.preventDefault() const data = new FormData(event.currentTarget) if (data.get('username') === 'admin') { setErrors({ username: '该用户名已被占用,请换一个。(本地模拟业务校验)' }) setResult(null) return } setErrors({}) const entries = [...new Set(data.keys())].map((key) => { const values = data.getAll(key).map((value) => typeof value === 'string' ? value : value.name) return [key, key === 'password' && values[0] ? '••••••••' : values.length === 1 ? values[0] : values] }) setResult(Object.fromEntries(entries)) }}>
Spectrum 表单示例

校验与提交

用户名和邮箱为必填项。可以直接提交,体验错误提示和焦点定位。

我已了解这是本地表单示例

提交结果

{result ? '校验通过,以下为本次提交的数据。' : '填写表单并提交后,在这里查看结果。'}

{result &&
{JSON.stringify(result, null, 2)}
}
) } export default function FormExamples() { const [version, setVersion] = useState(0) return setVersion((value) => value + 1)} /> }