# 表单组件

## `<input>`

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| ref | Ref\<InputRef\> | - | 实例 ref |
| value | string | - | 受控值 |
| defaultValue | string | - | 非受控默认值 |
| placeholder | string | - | 占位文本 |
| type | `'text' \| 'number' \| 'digit' \| 'password' \| 'tel' \| 'email'` | `'text'` | 输入类型 |
| maxlength | number | 140 | 最大长度 |
| disabled | boolean | false | 禁用 |
| readonly | boolean | false | 只读 |
| confirmType | `'send' \| 'search' \| 'go' \| 'done' \| 'next'` | `'send'` | 键盘确认按钮类型 |
| showSoftInputOnFocus | boolean | true | 聚焦时是否显示软键盘 |
| onInput | (e: BaseEvent\<'bindinput', InputInputEvent\>) => void | - | 输入变化，取值 `e.detail.value` |
| onFocus | (e: BaseEvent\<'bindfocus', InputFocusEvent\>) => void | - | 聚焦 |
| onBlur | (e: BaseEvent\<'bindblur', InputBlurEvent\>) => void | - | 失焦 |
| onConfirm | (e: BaseEvent\<'bindconfirm', InputConfirmEvent\>) => void | - | 点击确认按钮 |
| className | string | - | 样式类名 |
| style | CSSProperties | - | 内联样式 |

### InputRef 方法

| 方法 | 类型 | 说明 |
|------|------|------|
| setValue | (value: string) => Promise\<void\> | 设置值 |
| getValue | () => Promise\<{ value: string; selectionStart: number; selectionEnd: number }\> | 获取值和选区 |
| focus | () => Promise\<void\> | 聚焦 |
| blur | () => Promise\<void\> | 失焦 |

```tsx
import type { InputRef } from '@doubao-dev/framework/components';
import { useState, useRef } from '@byted-lynx/react';

// 受控
const [val, setVal] = useState('');
<input value={val} onInput={(e) => setVal(e.detail.value)} placeholder="请输入" />

// 通过 ref 控制
const inputRef = useRef<InputRef>(null);
<input ref={inputRef} placeholder="请输入" />
<button onClick={() => inputRef.current?.focus()}>聚焦</button>

// 密码输入
<input type="password" maxlength={20} placeholder="请输入密码" />
```

---

## `<textarea>`

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| placeholder | string | - | 占位文本 |
| maxlength | number | 140 | 最大长度 |
| maxlines | number | - | 最大行数 |
| lineSpacing | number \| `${number}px` \| `${number}rpx` | - | 行间距 |
| disabled | boolean | false | 禁用 |
| readonly | boolean | false | 只读 |
| confirmType | `'send' \| 'search' \| 'go' \| 'done' \| 'next'` | `'done'` | 确认按钮类型 |
| showSoftInputOnFocus | boolean | true | 聚焦时显示软键盘 |
| bounces | boolean | true | iOS 弹性效果 |
| onInput | (e: TextAreaInputEvent) => void | - | 输入变化 |
| onFocus | (e: TextAreaFocusEvent) => void | - | 聚焦 |
| onBlur | (e: TextAreaBlurEvent) => void | - | 失焦 |
| onConfirm | (e: TextAreaConfirmEvent) => void | - | 点击确认按钮 |
| className | string | - | 样式类名 |
| style | CSSProperties | - | 内联样式 |

```tsx
<textarea
  placeholder="请输入内容"
  maxlength={500}
  maxlines={5}
  onInput={(e) => console.log(e.detail.value)}
/>
```

---

## `<picker-view>` / `<picker-column>` / `<picker-divider>`

嵌入页面的滚动选择器。

**关键约束：**
- `picker-view` 高度必须用 **inline `style.height`** 传入，不能只写在 CSS class 中，否则内部 JS 无法同步读取高度，offset 回退为 108px
- `itemHeight` 要与 `style.height` 配合设置

### picker-view 属性

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| style | CSSProperties | - | **height 必须 inline 传入** |
| itemHeight | number | 36 | 单个选项高度 (px) |
| theme | `'light' \| 'dark'` | - | 未传时跟随宿主主题 |
| onChange | (values: (string \| number)[], options: PickerColumnOption[]) => void | - | 所有列选中项变化 |
| className | string | - | 样式类名 |

### picker-column 属性

| 属性 | 类型 | 说明 |
|------|------|------|
| options | `{ label: string; value: string \| number; disabled?: boolean }[]` | 列数据 |
| value | string \| number | 受控当前值 |
| defaultValue | string \| number | 非受控默认值 |
| onChange | (value: string \| number, option: PickerColumnOption) => void | 当前列变化 |
| className | string | 列的类名 |
| style | CSSProperties | 列的样式 |

### picker-divider 属性

| 属性 | 类型 | 说明 |
|------|------|------|
| text | string | 展示文本 |
| children | ReactNode | 自定义内容，优先级高于 text |
| className | string | 类名 |
| style | CSSProperties | 样式 |

`picker-divider` 不参与值计算，不会出现在 `onChange` 的 values/options 中。

```tsx
const hours = Array.from({ length: 24 }, (_, i) => ({ label: String(i).padStart(2, '0'), value: i }));
const minutes = ['00', '15', '30', '45'].map(v => ({ label: v, value: v }));

// 时间选择器（带分隔符）
<picker-view
  style={{ height: '216px' }}
  itemHeight={36}
  onChange={(values) => console.log('选中:', values)}
>
  <picker-column options={hours} defaultValue={10} />
  <picker-divider text=":" />
  <picker-column options={minutes} defaultValue="00" />
</picker-view>

// 年月日选择器
const years = Array.from({ length: 10 }, (_, i) => ({ label: `${2020 + i}年`, value: 2020 + i }));
const months = Array.from({ length: 12 }, (_, i) => ({ label: `${i + 1}月`, value: i + 1 }));

<picker-view style={{ height: '216px' }} itemHeight={36}>
  <picker-column options={years} defaultValue={2024} />
  <picker-column options={months} defaultValue={1} />
</picker-view>
```
