# Cascade

级联选择组件，用于从多层级数据中逐级选择。支持单选、多选、懒加载等模式。

## 适用场景

- 省市区等多级地址选择
- 组织架构层级选择
- 分类目录逐级筛选
- 需要懒加载的大数据量层级选择

## Props - Cascade

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| renderSelected | `(selected: CascadeOption[]) => ReactNode` | `-` | 否 | 已选择渲染器 |
| size | `"xs" \| "sm" \| "md" \| "lg"` | `-` | 否 | 尺寸 |
| mode | `"single" \| "multiple"` | `-` | 否 | 选择模式 |
| value | `ObjectId[] \| ObjectId[][]` | `-` | 否 | 选中项 value 控制值 |
| defaultValue | `ObjectId[] \| ObjectId[][]` | `-` | 否 | 选中项 value 默认值 |
| options | `CascadeOption[] \| ((value?: ObjectId) => Promise<CascadeOption[]>)` | `-` | 否 | 选项，支持静态全量或懒加载 async getter |
| expandTrigger | `"click" \| "hover"` | `-` | 否 | 展开次级触发类型 |
| selectOnExpand | `boolean` | `-` | 否 | 是否在展开时进行点选，用于允许选择非叶子节点，仅单选模式有效 |
| harmonizeSelections | `boolean` | `true` | 否 | 联动父子选择/反选，仅多选模式有效，懒加载时无效 |
| onExpand | `(value: ObjectId[], expandedChain: CascadeOption[]) => void` | `-` | 否 | 展开下一级时的回调 |
| onChange | `(value, enhancedOptionValue, selected) => void` | `-` | 否 | 值变化时的回调 |
| placeholder | `string` | `-` | 否 | 未选择占位提示 |
| disabled | `boolean` | `false` | 否 | 是否禁用 |
| status | `SelectStatus` | `"normal"` | 否 | 下拉框状态 |
| suffix | `ReactNode` | `-` | 否 | 自定义后缀 |
| withClear | `boolean` | `true` | 否 | 是否使用清除按钮 |
| onFocus | `FocusEventHandler<Element>` | `-` | 否 | 聚焦回调 |
| onBlur | `FocusEventHandler<Element>` | `-` | 否 | 失焦回调 |
| placement | `Placement` | `"bottom-start"` | 否 | popper 位置 |

## Props - CascadePanel

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| value | `ObjectId[] \| ObjectId[][]` | `-` | 否 | 选中项 value 控制值 |
| defaultValue | `ObjectId[] \| ObjectId[][]` | `-` | 否 | 选中项 value 默认值 |
| mode | `"single" \| "multiple"` | `"single"` | 否 | 选择模式 |
| options | `CascadeOption[] \| ((value?: ObjectId) => Promise<CascadeOption[]>)` | `-` | 否 | 选项，支持静态全量或懒加载 async getter |
| expandTrigger | `"click" \| "hover"` | `"click"` | 否 | 展开次级触发类型 |
| size | `"sm" \| "md"` | `-` | 否 | 尺寸，默认使用 config context `baseSize` |
| onExpand | `(value: ObjectId[], expandedChain: CascadeOption[]) => void` | `-` | 否 | 展开下一级时的回调 |
| onChange | `(value, enhancedOptionValue, selected) => void` | `-` | 否 | 值变化时的回调 |
| selectOnExpand | `boolean` | `false` | 否 | 是否在展开时进行点选，仅单选模式有效 |
| harmonizeSelections | `boolean` | `true` | 否 | 联动父子选择/反选，仅多选模式有效 |

## 典型用法

### 基础用法（单选/多选）

```tsx
import {useState} from 'react'
import {Cascade} from '@befe/brick'

const cityOptions = [
    {
        value: 'guangdong', label: '广东省',
        children: [
            {value: 'guangzhou', label: '广州市', children: [
                {value: 'liwan', label: '荔湾区'},
                {value: 'yuxiu', label: '越秀区'},
            ]},
        ],
    },
]

const [value, setValue] = useState([])

<Cascade
    mode={'single'}
    options={cityOptions}
    value={value}
    onChange={setValue}
/>
<Cascade
    mode={'multiple'}
    options={cityOptions}
    value={value}
    onChange={setValue}
    harmonizeSelections
/>
```

### Hover 展开

```tsx
<Cascade
    options={cityOptions}
    expandTrigger={'hover'}
    placeholder={'hover to expand'}
/>
```

### 允许选择非叶子节点

> 适用于允许选择非叶子节点的情况，仅在单选模式有效

```tsx
<Cascade options={cityOptions} selectOnExpand />
<Cascade options={cityOptions} selectOnExpand expandTrigger={'hover'} />
```

### 自定义已选显示

> 有时只需显示选择结果的末端节点

```tsx
<Cascade
    options={cityOptions}
    renderSelected={(selectedChain) => selectedChain[selectedChain.length - 1]?.label}
/>
```

### 懒加载 Options

> `options` 接受异步函数，需用 `option.isLeaf` 明确是否为叶子节点

```tsx
function fetchOptions(value?: string): Promise<CascadeOption[]> {
    return api.getChildren(value)
}

<Cascade options={fetchOptions} value={value} onChange={setValue} />
```

### 面板模式

```tsx
import {CascadePanel} from '@befe/brick'

<CascadePanel
    options={cityOptions}
    value={value}
    onChange={setValue}
    mode={'single'}
/>
```

## 注意事项

- 值类型：单选为 `ObjectId[]`（完整级联路径），多选为 `ObjectId[][]`（多条级联路径）
- 联动模式（harmonizeSelections）下，全选/反选不包含 disabled 节点，且懒加载时无效
- 懒加载时需用 `option.isLeaf` 明确是否为叶子节点；`isLeaf` 为 `false` 且 children 为空时才加载子节点
- Cascade 在 didMount 阶段会无参数调用一次 `props.options()` 以获取首层选项
- `expandTrigger="hover"` 配合 `selectOnExpand` 时，hover 只触发展开，不会执行 select
