# Select

下拉选择组件，支持单选和多选模式，支持分组选项和自定义选项内容。

## 适用场景

- 从预定义选项列表中选择一个或多个值
- 表单中的下拉选择字段
- 需要分组展示选项的场景
- 需要自定义选项内容或自定义已选展示的场景

## Props

### Select Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| mode | `"single" \| "multiple"` | `"single"` | 否 | 选择模式 |
| value | `SelectValue` | `-` | 否 | 选中控制值。单选：`null` 为"未选择"，`undefined` 为不控制；多选：`[]` 为"未选择" |
| defaultValue | `SelectValue` | `-` | 否 | 选中默认值。单选"未选择"为 `null`，多选为 `[]` |
| options | `SelectOptionObject[]` | `-` | 否 | 选项列表 |
| maxNumber | `number` | `-` | 否 | 最大选择个数，mode 为 multiple 时有效 |
| placement | `Placement` | `-` | 否 | 选项列表弹出位置 |
| onChange | `(value: SelectValue) => void` | `-` | 否 | 值变化时的回调 |
| renderSelected | `(selectedOptions) => ReactNode` | `-` | 否 | 已选择渲染器，返回的 ReactNode 必须是 inline element |
| withClear | `boolean` | `true` | 否 | 是否使用清除按钮，只对 mode single 有效；多选的整体清除入口为内置行为（有已选值且未禁用时自动显示），不受此 prop 控制 |
| withSelectAll | `boolean` | `true` | 否 | 是否使用全选，只对 mode multiple 有效 |
| allSelectedLabel | `string` | `-` | 否 | 已选择"全部"展示文字 |
| fixDropdownWidth | `boolean` | `-` | 否 | 将选项列表的宽度固定为 selection 宽度 |
| placeholder | `string` | `-` | 否 | 未选择占位提示 |
| size | `"xs" \| "sm" \| "md" \| "lg"` | `-` | 否 | 尺寸 |
| disabled | `boolean` | `false` | 否 | 是否禁用 |
| status | `SelectStatus` | `"normal"` | 否 | 下拉框状态 |
| suffix | `ReactNode` | `-` | 否 | 自定义后缀（一般为 Icon） |
| bordered | `boolean` | `-` | 否 | 是否有边框 |
| onFocus | `FocusEventHandler<Element>` | `-` | 否 | 聚焦回调 |
| onBlur | `FocusEventHandler<Element>` | `-` | 否 | 失焦回调 |
| suffixArrow | `FC<{}>` | `-` | 否 | 自定义下拉箭头图标 |
| suffixArrowExpanded | `FC<{}>` | `-` | 否 | 自定义展开时的下拉箭头图标，未定义时使用 suffixArrow |

### SelectOptionObject Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| value | `MenuItemId` | `-` | 是 | 选项值 |
| label | `string` | `-` | 否 | 选项显示值，select 框"选中值"以该值展示 |
| content | `ReactNode` | `-` | 否 | 下拉选项显示内容，用于更复杂的选项显示，仍需提供 label |
| disabled | `boolean` | `-` | 否 | 是否禁用 |
| children | `SelectOptionObject[]` | `-` | 否 | 子选项（用于分组） |

### SelectSelection Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| placeholder | `string` | `-` | 否 | 未选择占位提示 |
| size | `"xs" \| "sm" \| "md" \| "lg"` | `-` | 否 | 尺寸 |
| selectedStats | `string` | `-` | 否 | 多选模式选择个数统计 |
| disabled | `boolean` | `false` | 否 | 是否禁用 |
| status | `SelectStatus` | `"normal"` | 否 | 下拉框状态 |
| selectedContent | `ReactNode` | `-` | 否 | 已选择显示内容 |
| suffix | `ReactNode` | `-` | 否 | 自定义后缀 |
| withClear | `boolean` | `true` | 否 | 是否使用清除按钮 |
| refClearButtonElement | `Ref<HTMLButtonElement>` | `-` | 否 | ref 到清除按钮的 HTMLElement |
| onClickClear | `(e: MouseEvent) => void \| Promise` | `-` | 否 | 点击清除按钮回调 |
| expanded | `boolean` | `-` | 否 | 是否处于展开状态 |
| bordered | `boolean` | `true` | 否 | 是否有边框 |
| onFocus | `FocusEventHandler<Element>` | `-` | 否 | 聚焦回调 |
| onBlur | `FocusEventHandler<Element>` | `-` | 否 | 失焦回调 |
| onKeyDown | `KeyboardEventHandler<Element>` | `-` | 否 | 键盘按下回调 |
| selectedTitle | `string` | `-` | 否 | 已选内容的 title tip |
| suffixArrow | `FC<{}>` | `-` | 否 | 自定义下拉箭头图标 |
| suffixArrowExpanded | `FC<{}>` | `-` | 否 | 自定义展开时的下拉箭头图标 |

### SelectOption Props（JSX 子元素用法）

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| value | `MenuItemId` | `-` | 是 | 选项的值，亦是选项的唯一标识 |
| label | `string` | `-` | 否 | 选项的显示文字，不指定则从 children 提取 |
| type | `"normal" \| "checkbox"` | `-` | 否 | 类型 |
| disabled | `boolean` | `-` | 否 | 是否禁用 |
| suffix | `ReactNode` | `-` | 否 | 后缀内容 |
| suffixArrow | `boolean \| SvgFC` | `-` | 否 | 后缀箭头 |
| onClick | `(e: MouseEvent) => void` | `-` | 否 | 点击回调 |
| prefix | `ReactNode` | `-` | 否 | 前缀内容 |
| href | `string` | `-` | 否 | 链接跳转地址 |
| target | `string` | `-` | 否 | 链接跳转 target |
| indeterminate | `boolean` | `-` | 否 | 是否部分选中 |
| suffixLoading | `boolean \| SvgFC` | `-` | 否 | 后缀 loading，用于懒加载时体现 loading 状态 |
| selected | `boolean` | `-` | 否 | 是否选中控制值 |
| icon | `SvgFC` | `-` | 否 | 前缀 icon，只在第一层 Menu 下有效 |

### SelectOptionGroup Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| label | `ReactNode` | `-` | 否 | 显示值 |
| suffix | `ReactNode` | `-` | 否 | 后缀内容 |
| prefix | `ReactNode` | `-` | 否 | 前缀内容 |
| icon | `SvgFC` | `-` | 否 | 前缀 icon，只在第一层 Menu 下有效 |

## 典型用法

### 基础单选

```tsx
import { useState } from 'react'
import { Select, SelectOptionObject, SelectValue } from '@befe/brick'

const options: SelectOptionObject[] = [
    { value: '', label: 'option_1' },
    {
        value: 'group_1',
        label: '分类一',
        children: [
            { value: 'option_2', label: 'option_2' },
            { value: 'option_3', label: 'option_3' },
        ],
    },
    {
        value: 'group_no_name',
        children: [
            { value: 'option_4', label: 'option_4' },
            { value: 'option_5', label: 'option_5', disabled: true },
        ],
    },
]

function Demo() {
    const [value, setValue] = useState<SelectValue>(null)

    return (
        <Select
            value={value}
            options={options}
            onChange={setValue}
            placeholder="请选择"
        />
    )
}
```

### 多选

```tsx
function Demo() {
    return (
        <div>
            <Select options={options} mode="multiple" placeholder="多选" />
            <Select options={options} mode="multiple" maxNumber={2} placeholder="最多选择2个" />
        </div>
    )
}
```

### JSX 子元素用法

```tsx
import { Select, Option } from '@befe/brick'

function Demo() {
    return (
        <Select size="md" placeholder="请选择">
            <Option value="option_1" label="option-1">opt-1-content</Option>
            <Option value="option_2" label="option-2">opt-2-content</Option>
            <Option value="option_3" label="option-3">opt-3-content</Option>
        </Select>
    )
}
```

### 无边框

```tsx
<Select value={value} bordered={false} options={options} onChange={setValue} placeholder="请选择" />
```

## 注意事项

- `SelectOption` 使用 `value` 字段作为唯一标识（与 HTML select option 保持一致），而非 `id`
- 单选模式下 `value` 区分 `null`（控制值"未选择"）和 `undefined`（不控制）
- 多选模式下"未选择"控制值为 `[]`
- `content` 用于自定义下拉选项的显示，但仍需提供 `label` 作为选中后的展示文字
- `renderSelected` 返回的 ReactNode 必须是 inline element，以保证 selection 框内的 ellipsis 样式
- 多选模式下，存在已选值且未禁用时会自动出现整体清除入口，一键清空全部已选项，无需配置 `withClear`
