aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/components/form-examples/color-file-fields.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/form-examples/color-file-fields.tsx')
-rw-r--r--src/components/form-examples/color-file-fields.tsx69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/components/form-examples/color-file-fields.tsx b/src/components/form-examples/color-file-fields.tsx
new file mode 100644
index 0000000..e9d0e74
--- /dev/null
+++ b/src/components/form-examples/color-file-fields.tsx
@@ -0,0 +1,69 @@
+import FieldGrid from './field-grid'
+import { useState } from 'react'
+import { ColorArea, parseColor } from '@react-spectrum/s2/ColorArea'
+import { ColorField } from '@react-spectrum/s2/ColorField'
+import { ColorSlider } from '@react-spectrum/s2/ColorSlider'
+import { ColorWheel } from '@react-spectrum/s2/ColorWheel'
+import { ColorSwatch, ColorSwatchPicker } from '@react-spectrum/s2/ColorSwatchPicker'
+import { DropZone } from '@react-spectrum/s2/DropZone'
+import { FileTrigger } from '@react-spectrum/s2/FileTrigger'
+import { Button } from '@react-spectrum/s2/Button'
+import styles from './form-examples.module.css'
+
+export default function ColorFileFields({ disabled }: { disabled: boolean }) {
+ const [color, setColor] = useState(() => parseColor('hsl(265, 75%, 60%)'))
+ const [files, setFiles] = useState<File[]>([])
+ const [fileError, setFileError] = useState('')
+ return (
+ <>
+ <section className={styles.section} aria-labelledby="color-fields-title">
+ <h2 id="color-fields-title">颜色选择</h2>
+ <p>输入框、色板、色轮和滑块共享同一个颜色值。</p>
+ <FieldGrid>
+ <ColorField label="颜色值" value={color} onChange={(next) => { if (next) setColor(next) }} />
+ <ColorSlider isDisabled={disabled} label="色相" channel="hue" colorSpace="hsl" value={color} onChange={setColor} />
+ <ColorSlider isDisabled={disabled} label="透明度" channel="alpha" value={color} onChange={setColor} />
+ <div className={styles.stack}>
+ <span>预设色板</span>
+ <ColorSwatchPicker value={color} onChange={setColor}>
+ <ColorSwatch color="#8b5cf6" /><ColorSwatch color="#3b82f6" /><ColorSwatch color="#22c55e" /><ColorSwatch color="#f97316" />
+ </ColorSwatchPicker>
+ </div>
+ </FieldGrid>
+ <div className={styles.calendars}>
+ <div className={styles.stack}><span id="color-area-label">二维颜色面板</span><ColorArea isDisabled={disabled} aria-labelledby="color-area-label" colorSpace="hsl" xChannel="saturation" yChannel="lightness" value={color} onChange={setColor} /></div>
+ <div className={styles.stack}><span id="color-wheel-label">色轮</span><ColorWheel isDisabled={disabled} aria-labelledby="color-wheel-label" value={color} onChange={setColor} /></div>
+ </div>
+ <input type="hidden" name="color" value={color.toString('hexa')} />
+ <output className={styles.output}>{color.toString('hexa')}</output>
+ </section>
+ <section className={styles.section} aria-labelledby="file-fields-title">
+ <h2 id="file-fields-title">文件选择与拖放</h2>
+ <DropZone aria-label="附件拖放区域" getDropOperation={(types) => !disabled && types.has('Files') ? 'copy' : 'cancel'}
+ onDrop={async (event) => {
+ try {
+ const next = await Promise.all(event.items.filter((item) => item.kind === 'file').map((item) => item.getFile()))
+ setFiles(next)
+ setFileError('')
+ } catch {
+ setFileError('无法读取文件,请重新选择。')
+ }
+ }}>
+ <div className={styles.dropContent}>
+ <p>将文件拖放到这里,或从设备中选择。</p>
+ <FileTrigger allowsMultiple onSelect={(selected) => { if (selected) { setFiles(Array.from(selected)); setFileError('') } }}>
+ <Button type="button" variant="secondary">选择文件</Button>
+ </FileTrigger>
+ <p>仅在本页预览文件信息,不上传。</p>
+ </div>
+ </DropZone>
+ {fileError && <p role="alert">{fileError}</p>}
+ <div aria-live="polite">
+ {files.length ? <ul>{files.map((file, index) => <li key={`${file.name}-${index}`}>{file.name} · {Math.ceil(file.size / 1024)} KB</li>)}</ul> : <p>尚未选择文件。</p>}
+ </div>
+ {files.length > 0 && <Button type="button" variant="secondary" onPress={() => setFiles([])}>清空文件</Button>}
+ <input type="hidden" name="files" value={JSON.stringify(files.map(({ name, size, type }) => ({ name, size, type })))} />
+ </section>
+ </>
+ )
+}