From 481402e09fe760634b826b09e302e2e1bfec88b1 Mon Sep 17 00:00:00 2001 From: shu Date: Mon, 7 Sep 2026 15:48:36 +0800 Subject: feat: initialize React Spectrum template with layouts and showcases --- src/components/form-examples/form-examples.tsx | 91 ++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/components/form-examples/form-examples.tsx (limited to 'src/components/form-examples/form-examples.tsx') diff --git a/src/components/form-examples/form-examples.tsx b/src/components/form-examples/form-examples.tsx new file mode 100644 index 0000000..e1dd6c8 --- /dev/null +++ b/src/components/form-examples/form-examples.tsx @@ -0,0 +1,91 @@ +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)} /> +} -- cgit v1.2.3