---
nav:
  title: 组件
  order: 1
group:
  title: Data Entry
  order: 1
title: Selector
order: 1
category: pro
---

# Selector 选择器

功能强大的选项选择组件，支持单选、多选、数量选择等多种模式，提供丰富的视觉样式和联动能力。

## 何时使用

- 需要从多个选项中选择一个或多个的场景
- 需要控制选项数量的商品/套餐选择场景
- 需要多组选项联动的复杂表单场景
- 需要展示丰富视觉效果的选项卡片场景

## 代码演示

### 📦 快速上手 - Preset 预设模式

适合非专业开发人员，通过 `preset` 属性快速应用预设样式，无需关心复杂的布局配置。

#### Preset 快速入门

使用 `preset={{ variant: '1' }}` 即可快速应用预设布局，无需任何 `layout` 配置。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="选择主菜"
      dataSource={[
        { id: 1, title: '汉堡' },
        { id: 2, title: '披萨' },
        { id: 3, title: '意面' },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="default"
      preset={{ variant: '1' }}
    />
  );
};
```

#### 主题色覆盖（token）

使用 `theme.token.colorPrimary` 可覆盖组件主题主色，组件会基于该值，使用antd算法生成一套token供内部样式使用。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);
  const [colorPrimary, setColorPrimary] = useState('#5D3F9F');

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <input
        type="color"
        value={colorPrimary}
        onChange={(e) => setColorPrimary(e.target.value)}
        style={{ width: 48, height: 32, padding: 0, border: 'none' }}
      />
      <Selector
        title="选择主菜"
        dataSource={[
          { id: 1, title: '汉堡' },
          { id: 2, title: '披萨' },
          { id: 3, title: '意面' },
        ]}
        mode="single"
        valueType="primitive"
        fieldNames={{ value: 'id', label: 'title' }}
        value={value}
        onChange={setValue}
        variant="default"
        preset={{ variant: '1' }}
        theme={{ token: { colorPrimary } }}
      />
    </div>
  );
};
```

#### Default Variant - 基础样式预设

Default 变体支持 4 种预设布局，适用于常规的选项选择场景。

**Preset 1 - 单列布局**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const dataSource = [
    { id: 1, title: '选项A' },
    { id: 2, title: '选项B' },
    { id: 3, title: '选项C' },
  ];

  return (
    <Selector
      dataSource={dataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="default"
      preset={{ variant: '1' }} // 100% 宽度，垂直排列
    />
  );
};
```

**Preset 2 - 自适应宽度**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const dataSource = [
    { id: 1, title: '选项A' },
    { id: 2, title: '选项B' },
    { id: 3, title: '选项C' },
  ];

  return (
    <Selector
      dataSource={dataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="default"
      preset={{ variant: '2' }} // Flex 布局，选项宽度自动适应内容
    />
  );
};
```

#### Card Variant - 卡片样式预设

Card 变体支持 5 种预设布局，适用于卡片式、套餐式的选项展示。

**Preset 1 - 固定宽度网格（209px）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const cardDataSource = [
    {
      id: 1,
      title: '基础版',
      price: '¥99/月',
      desc: '适合个人用户',
    },
    {
      id: 2,
      title: '专业版',
      price: '¥299/月',
      desc: '适合小团队',
    },
    {
      id: 3,
      title: '企业版',
      price: '¥999/月',
      desc: '适合大型企业',
    },
  ];

  return (
    <Selector
      dataSource={cardDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '1' }} // CSS Grid 布局，每列固定 209px
    />
  );
};
```

**Preset 2 - 固定宽度网格 + Filled 指示器**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const cardDataSource = [
    { id: 1, title: '基础版', price: '¥99/月' },
    { id: 2, title: '专业版', price: '¥299/月' },
    { id: 3, title: '企业版', price: '¥999/月' },
  ];

  return (
    <Selector
      dataSource={cardDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '2' }} // 209px Grid + filled 风格指示器
    />
  );
};
```

**Preset 3 - 单列卡片布局**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const cardDataSource = [
    { id: 1, title: '基础版', price: '¥99/月', desc: '适合个人用户' },
    { id: 2, title: '专业版', price: '¥299/月', desc: '适合小团队' },
    { id: 3, title: '企业版', price: '¥999/月', desc: '适合大型企业' },
  ];

  return (
    <Selector
      dataSource={cardDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '3' }} // 100% 宽度，适合横向卡片
      itemProps={{
        layout: 'horizontal',
        renderContent: (option) => (
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 16, fontWeight: 600 }}>
              {option.dataSource.title}
            </div>
            <div style={{ color: '#ff4d4f', fontSize: 18, margin: '4px 0' }}>
              {option.dataSource.price}
            </div>
            <div style={{ color: '#999', fontSize: 13 }}>
              {option.dataSource.desc}
            </div>
          </div>
        ),
      }}
    />
  );
};
```

**Preset 4 - 大尺寸网格（325px）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const cardDataSource = [
    {
      id: 1,
      title: '基础版',
      price: '¥99/月',
      desc: '适合个人用户',
      features: ['5GB 存储', '基础功能'],
    },
    {
      id: 2,
      title: '专业版',
      price: '¥299/月',
      desc: '适合小团队',
      features: ['50GB 存储', '高级功能'],
    },
  ];

  return (
    <Selector
      dataSource={cardDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '4' }} // 每列固定 325px（适合内容丰富的卡片）
      itemProps={{
        renderContent: (option) => (
          <div>
            <div style={{ fontSize: 20, fontWeight: 600, marginBottom: 12 }}>
              {option.dataSource.title}
            </div>
            <div style={{ color: '#ff4d4f', fontSize: 24, marginBottom: 12 }}>
              {option.dataSource.price}
            </div>
            <div style={{ color: '#666', fontSize: 14, marginBottom: 16 }}>
              {option.dataSource.desc}
            </div>
            <div style={{ fontSize: 13, color: '#333', lineHeight: 1.8 }}>
              {option.dataSource.features?.map((f, i) => (
                <div key={i}>✓ {f}</div>
              ))}
            </div>
          </div>
        ),
      }}
    />
  );
};
```

**Preset 5 - 单列大卡片**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const cardDataSource = [
    { id: 1, title: '基础版', price: '¥99/月', desc: '适合个人用户' },
    { id: 2, title: '专业版', price: '¥299/月', desc: '适合小团队' },
  ];

  return (
    <Selector
      dataSource={cardDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '5' }} // 100% 宽度，适合详细信息展示
      itemProps={{
        layout: 'horizontal',
        renderContent: (option) => (
          <div style={{ flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 18, fontWeight: 600, marginBottom: 4 }}>
                  {option.dataSource.title}
                </div>
                <div style={{ color: '#999', fontSize: 14 }}>
                  {option.dataSource.desc}
                </div>
              </div>
              <div style={{ color: '#ff4d4f', fontSize: 24, fontWeight: 600 }}>
                {option.dataSource.price}
              </div>
            </div>
          </div>
        ),
      }}
    />
  );
};
```

#### Media Variant - 媒体样式预设

Media 变体支持 2 种预设布局，适用于图片、视频等媒体内容的选择场景。

**Preset 1 - 自适应媒体网格**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState([1]);

  const mediaDataSource = [
    {
      id: 1,
      label: '风景',
      value: 'landscape',
      cover: 'https://picsum.photos/seed/landscape/300/200',
    },
    {
      id: 2,
      label: '人物',
      value: 'portrait',
      cover: 'https://picsum.photos/seed/portrait/300/200',
    },
    {
      id: 3,
      label: '建筑',
      value: 'architecture',
      cover: 'https://picsum.photos/seed/architecture/300/200',
    },
  ];

  return (
    <Selector
      dataSource={mediaDataSource}
      mode="multiple"
      valueType="primitive"
      fieldNames={{ value: 'value', label: 'label', cover: 'cover' }}
      value={value}
      onChange={setValue}
      variant="media"
      preset={{ variant: '1' }} // Flex 布局，自动应用 filled 指示器
    />
  );
};
```

**Preset 2 - 自适应媒体网格（变体）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  const mediaDataSource = [
    {
      id: 1,
      label: '风景',
      value: 'landscape',
      cover: 'https://picsum.photos/seed/landscape/300/200',
    },
    {
      id: 2,
      label: '人物',
      value: 'portrait',
      cover: 'https://picsum.photos/seed/portrait/300/200',
    },
  ];

  return (
    <Selector
      dataSource={mediaDataSource}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'value', label: 'label', cover: 'cover' }}
      value={value}
      onChange={setValue}
      variant="media"
      preset={{ variant: '2' }} // 另一种 Flex 媒体布局
    />
  );
};
```

#### Select Variant - 下拉选择预设

Select 变体提供标准的下拉选择器样式。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState();

  return (
    <Selector
      title="选择城市"
      dataSource={[
        { id: 1, title: '北京', value: 'beijing' },
        { id: 2, title: '上海', value: 'shanghai' },
        { id: 3, title: '广州', value: 'guangzhou' },
      ]}
      mode="single"
      valueType="primitive"
      variant="select"
      preset={{ variant: '1' }}
      fieldNames={{ value: 'value', label: 'title' }}
      value={value}
      onChange={setValue}
    />
  );
};
```

#### 实际应用场景

**场景1：电商商品规格选择**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';
import { StarOutlined } from '@ant-design/icons';

export default () => {
  const [value, setValue] = useState({ value: 1, quantity: 1 });

  const productSpecs = [
    {
      id: 1,
      title: '128GB 黑色',
      price: '¥5999',
      stock: 156,
      ruleConfig: { min: 1, max: 3 },
    },
    {
      id: 2,
      title: '256GB 白色',
      price: '¥6999',
      stock: 89,
      ruleConfig: { min: 1, max: 5 },
    },
    {
      id: 3,
      title: '512GB 蓝色',
      price: '¥7999',
      stock: 23,
      ruleConfig: { min: 1, max: 2 },
    },
  ];

  return (
    <Selector
      title="选择商品规格"
      dataSource={productSpecs}
      mode="single"
      valueType="object"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '1' }}
      itemProps={{
        layout: 'vertical',
        renderContent: (option) => (
          <div>
            <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>
              {option.dataSource.title}
            </div>
            <div
              style={{
                color: '#ff4d4f',
                fontSize: 20,
                fontWeight: 600,
                marginBottom: 6,
              }}
            >
              {option.dataSource.price}
            </div>
            <div style={{ color: '#999', fontSize: 13 }}>
              库存：{option.dataSource.stock} 件
            </div>
          </div>
        ),
      }}
      titleProps={{
        visible: true,
        icon: {
          visible: true,
          icon: <StarOutlined style={{ color: '#faad14' }} />,
        },
      }}
    />
  );
};
```

**场景2：支付方式选择**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState('alipay');

  const paymentMethods = [
    { id: 1, value: 'alipay', title: '支付宝', icon: '💳' },
    { id: 2, value: 'wechat', title: '微信支付', icon: '💚' },
    { id: 3, value: 'card', title: '银行卡', icon: '🏦' },
  ];

  return (
    <Selector
      title="选择支付方式"
      dataSource={paymentMethods}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'value', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '3' }}
      itemProps={{
        layout: 'horizontal',
        renderContent: (option) => (
          <div
            style={{
              display: 'flex',
              alignItems: 'center',
              gap: 12,
              flex: 1,
            }}
          >
            <div style={{ fontSize: 32 }}>{option.dataSource.icon}</div>
            <div style={{ fontSize: 16, fontWeight: 500 }}>
              {option.dataSource.title}
            </div>
          </div>
        ),
      }}
    />
  );
};
```

**场景3：增值服务选择（多选）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState([1, 2]);

  const serviceOptionsList = [
    { id: 1, title: '7天无理由退换', price: '免费' },
    { id: 2, title: '延保服务', price: '+¥199' },
    { id: 3, title: '碎屏险', price: '+¥299' },
    { id: 4, title: '上门安装', price: '+¥99' },
  ];

  return (
    <Selector
      title="增值服务（可选）"
      dataSource={serviceOptionsList}
      mode="multiple"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '3' }}
      ruleConfig={{ max: 3 }}
      itemProps={{
        layout: 'horizontal',
        renderContent: (option) => (
          <div
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
              flex: 1,
            }}
          >
            <div style={{ fontSize: 15 }}>{option.dataSource.title}</div>
            <div style={{ color: '#ff4d4f', fontSize: 15, fontWeight: 600 }}>
              {option.dataSource.price}
            </div>
          </div>
        ),
      }}
      titleProps={{
        visible: true,
        tip: {
          visible: true,
          text: '最多选择3项',
        },
      }}
    />
  );
};
```

### 🔧 高级配置 - 专业开发模式

适合专业开发人员，通过 `layout`、`renderItem` 等高级属性实现完全自定义。

#### 自定义布局配置

通过 `layout` 属性精确控制布局方式。推荐使用 `containerStyle` 直接传入 CSS 样式，更加灵活。

**Flex 布局（推荐）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="自定义 Flex 布局"
      dataSource={[
        { id: 1, title: '选项A' },
        { id: 2, title: '选项B' },
        { id: 3, title: '选项C' },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="default"
      layout={{
        containerStyle: {
          display: 'flex',
          flexDirection: 'row',
          flexWrap: 'wrap',
        },
        gutter: 16,
      }}
    />
  );
};
```

**CSS Grid 自动适应布局（推荐）**

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="自定义 Grid 布局"
      dataSource={[
        { id: 1, title: '选项A' },
        { id: 2, title: '选项B' },
        { id: 3, title: '选项C' },
        { id: 4, title: '选项D' },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      layout={{
        containerStyle: {
          display: 'grid',
          gridTemplateColumns:
            'repeat(auto-fit, minmax(min(200px, 100%), 1fr))',
        },
        gutter: 16,
      }}
    />
  );
};
```

**Ant Design Grid 布局**

适用于需要使用 Ant Design 响应式栅格系统的场景。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="Ant Design Grid 布局"
      dataSource={[
        { id: 1, title: '选项A' },
        { id: 2, title: '选项B' },
        { id: 3, title: '选项C' },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      layout={{
        type: 'antdGrid',
        columns: 3,
        gutter: [16, 16],
        colConfig: { xs: 24, sm: 12, md: 8 },
      }}
    />
  );
};
```

#### 完全自定义渲染

通过 `renderItem` 完全控制每个选项的渲染。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="完全自定义渲染"
      dataSource={[
        {
          id: 1,
          title: '基础套餐',
          price: '$9.99',
          desc: '适合个人使用',
          badge: 'HOT',
        },
        {
          id: 2,
          title: '标准套餐',
          price: '$19.99',
          desc: '适合小团队',
        },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      renderItem={({ dataSource, indicator, actions }) => (
        <div
          onClick={() => actions.toggle(dataSource._key)}
          style={{
            border: '2px solid',
            borderColor: dataSource.selected ? '#1890ff' : '#d9d9d9',
            borderRadius: 12,
            padding: 20,
            marginBottom: 12,
            cursor: 'pointer',
            position: 'relative',
            transition: 'all 0.3s',
            backgroundColor: dataSource.selected ? '#e6f7ff' : '#fff',
          }}
        >
          {dataSource.badge && (
            <div
              style={{
                position: 'absolute',
                top: -8,
                right: 20,
                background: '#ff4d4f',
                color: '#fff',
                padding: '2px 12px',
                borderRadius: 10,
                fontSize: 12,
                fontWeight: 600,
              }}
            >
              {dataSource.badge}
            </div>
          )}
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div>{indicator}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 18, fontWeight: 600, marginBottom: 4 }}>
                {dataSource.title}
              </div>
              <div style={{ fontSize: 13, color: '#999' }}>
                {dataSource.desc}
              </div>
            </div>
            <div style={{ fontSize: 24, fontWeight: 700, color: '#1890ff' }}>
              {dataSource.price}
            </div>
          </div>
        </div>
      )}
    />
  );
};
```

#### 自定义指示器

通过 `indicatorProps` 自定义选中指示器的样式和行为。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';
import { CheckCircleFilled, StarFilled } from '@ant-design/icons';

export default () => {
  const [value, setValue] = useState(1);

  return (
    <Selector
      title="自定义指示器"
      dataSource={[
        { id: 1, title: '选项A' },
        { id: 2, title: '选项B' },
        { id: 3, title: '选项C' },
      ]}
      mode="single"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '1' }}
      indicatorProps={{
        variant: 'filled',
        render: ({ option, selected, disabled, actions }) => (
          <div
            onClick={() => !disabled && actions.toggle(option._key)}
            style={{
              fontSize: 24,
              color: selected ? '#faad14' : '#d9d9d9',
              cursor: disabled ? 'not-allowed' : 'pointer',
            }}
          >
            {selected ? <StarFilled /> : <CheckCircleFilled />}
          </div>
        ),
      }}
    />
  );
};
```

#### 数量选择器配置

配合 `valueType="object"` 使用数量选择器。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState([
    { value: 1, quantity: 2 },
    { value: 2, quantity: 1 },
  ]);

  return (
    <Selector
      title="选择商品和数量"
      dataSource={[
        {
          id: 1,
          title: '商品A',
          price: '¥99',
          ruleConfig: { min: 1, max: 5 },
        },
        {
          id: 2,
          title: '商品B',
          price: '¥199',
          ruleConfig: { min: 1, max: 3 },
        },
        {
          id: 3,
          title: '商品C',
          price: '¥299',
          ruleConfig: { min: 1, max: 10 },
        },
      ]}
      mode="multiple"
      valueType="object"
      fieldNames={{ value: 'id', label: 'title' }}
      value={value}
      onChange={setValue}
      variant="card"
      preset={{ variant: '3' }}
      showStepper={true}
      stepperProps={{
        size: 'middle',
        shape: 'square',
      }}
      itemProps={{
        layout: 'horizontal',
        renderContent: (option) => (
          <div
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
              flex: 1,
            }}
          >
            <div>
              <div style={{ fontSize: 16, fontWeight: 600 }}>
                {option.dataSource.title}
              </div>
              <div style={{ color: '#ff4d4f', fontSize: 18 }}>
                {option.dataSource.price}
              </div>
            </div>
          </div>
        ),
      }}
    />
  );
};
```

#### 必填校验

通过 `ruleConfig` 配置校验规则。

```tsx
import React, { useState, useRef } from 'react';
import { Selector } from '@pisell/private-materials';
import { Button, message } from 'antd';

export default () => {
  const [value, setValue] = useState();
  const selectorRef = useRef();

  const handleValidate = async () => {
    try {
      await selectorRef.current?.validate();
      message.success('校验通过');
    } catch (error) {
      message.error('校验失败');
    }
  };

  return (
    <>
      <Selector
        ref={selectorRef}
        title="选择主菜（必选）"
        dataSource={[
          { id: 1, title: '汉堡' },
          { id: 2, title: '披萨' },
        ]}
        mode="single"
        valueType="primitive"
        fieldNames={{ value: 'id', label: 'title' }}
        ruleConfig={{
          required: 1,
          autoValidate: true,
        }}
        variant="default"
        preset={{ variant: '1' }}
        value={value}
        onChange={setValue}
      />
      <Button onClick={handleValidate} style={{ marginTop: 16 }}>
        校验
      </Button>
    </>
  );
};
```

#### 最小/最大选择数量

限制多选模式下的选择数量范围。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState([]);

  return (
    <Selector
      title="选择配料（至少2个，最多4个）"
      dataSource={[
        { id: 1, title: '生菜' },
        { id: 2, title: '番茄' },
        { id: 3, title: '洋葱' },
        { id: 4, title: '芝士' },
        { id: 5, title: '培根' },
        { id: 6, title: '鸡蛋' },
      ]}
      mode="multiple"
      valueType="primitive"
      fieldNames={{ value: 'id', label: 'title' }}
      variant="card"
      preset={{ variant: '1' }}
      ruleConfig={{
        min: 2,
        max: 4,
        autoValidate: true,
      }}
      value={value}
      onChange={setValue}
    />
  );
};
```

#### 组内互斥

通过 `mutex` 配置组内互斥规则。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

export default () => {
  const [value, setValue] = useState([]);

  return (
    <Selector
      title="选择配置（温度和糖度互斥）"
      dataSource={[
        { id: 1, title: '热', value: 'hot' },
        { id: 2, title: '温', value: 'warm' },
        { id: 3, title: '冷', value: 'cold' },
        { id: 4, title: '少糖', value: 'less-sugar' },
        { id: 5, title: '正常糖', value: 'normal-sugar' },
        { id: 6, title: '多糖', value: 'more-sugar' },
      ]}
      mode="multiple"
      valueType="primitive"
      fieldNames={{ value: 'value', label: 'title' }}
      variant="default"
      preset={{ variant: '2' }}
      ruleConfig={{
        mutex: [
          ['hot', 'warm', 'cold'], // 温度互斥组
          ['less-sugar', 'normal-sugar', 'more-sugar'], // 糖度互斥组
        ],
      }}
      value={value}
      onChange={setValue}
    />
  );
};
```

#### 自定义校验器

通过 `customValidator` 实现复杂的校验逻辑。

```tsx
import React, { useState, useRef } from 'react';
import { Selector } from '@pisell/private-materials';
import { Button, message } from 'antd';

export default () => {
  const [value, setValue] = useState([]);
  const selectorRef = useRef();

  const handleValidate = async () => {
    try {
      await selectorRef.current?.validate();
      message.success('校验通过');
    } catch (error) {
      message.error(error.message || '校验失败');
    }
  };

  return (
    <>
      <Selector
        ref={selectorRef}
        title="选择配料（至少包含一个蔬菜）"
        dataSource={[
          { id: 1, title: '生菜', type: 'vegetable' },
          { id: 2, title: '番茄', type: 'vegetable' },
          { id: 3, title: '洋葱', type: 'vegetable' },
          { id: 4, title: '培根', type: 'meat' },
          { id: 5, title: '鸡蛋', type: 'protein' },
        ]}
        mode="multiple"
        valueType="primitive"
        fieldNames={{ value: 'id', label: 'title' }}
        variant="default"
        preset={{ variant: '2' }}
        ruleConfig={{
          customValidator: async (value) => {
            const selectedItems = Array.isArray(value) ? value : [value];
            const dataSource = [
              { id: 1, title: '生菜', type: 'vegetable' },
              { id: 2, title: '番茄', type: 'vegetable' },
              { id: 3, title: '洋葱', type: 'vegetable' },
              { id: 4, title: '培根', type: 'meat' },
              { id: 5, title: '鸡蛋', type: 'protein' },
            ];
            const hasVegetable = selectedItems.some((id) => {
              const item = dataSource.find((d) => d.id === id);
              return item?.type === 'vegetable';
            });
            if (!hasVegetable) {
              throw new Error('至少需要选择一个蔬菜');
            }
          },
        }}
        value={value}
        onChange={setValue}
      />
      <Button onClick={handleValidate} style={{ marginTop: 16 }}>
        校验
      </Button>
    </>
  );
};
```

## SelectorGroup 组联动

`SelectorGroup` 组件支持多个选择器组之间的联动效果。

### 基础组联动

多个选择器组组合使用。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

const SelectorGroup = Selector.Group;

export default () => {
  const [values, setValues] = useState({});

  const dataSource = [
    {
      id: 1,
      title: '主菜',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '汉堡' },
        { id: 2, title: '披萨' },
      ],
      ruleConfig: {
        required: 1,
      },
    },
    {
      id: 2,
      title: '配料',
      mode: 'multiple',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '生菜' },
        { id: 2, title: '番茄' },
        { id: 3, title: '芝士' },
      ],
    },
  ];

  return (
    <SelectorGroup
      dataSource={dataSource}
      value={values}
      onChange={setValues}
    />
  );
};
```

### 条件显示

根据选择结果动态显示/隐藏分组。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

const SelectorGroup = Selector.Group;

export default () => {
  const [values, setValues] = useState({});

  const dataSource = [
    {
      id: 1,
      title: '主菜',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'value', label: 'title' },
      dataSource: [
        { id: 1, title: '汉堡', value: 'burger' },
        { id: 2, title: '披萨', value: 'pizza' },
      ],
    },
    {
      id: 2,
      title: '汉堡定制',
      mode: 'multiple',
      valueType: 'primitive',
      fieldNames: { value: 'value', label: 'title' },
      dataSource: [
        { id: 1, title: '加倍牛肉', value: 'double-meat' },
        { id: 2, title: '额外芝士', value: 'extra-cheese' },
      ],
    },
    {
      id: 3,
      title: '披萨定制',
      mode: 'multiple',
      valueType: 'primitive',
      fieldNames: { value: 'value', label: 'title' },
      dataSource: [
        { id: 1, title: '薄底', value: 'thin-crust' },
        { id: 2, title: '额外芝士', value: 'extra-cheese' },
      ],
    },
  ];

  const linkageRules = [
    {
      type: 'expr',
      when: {
        and: [{ groupId: '1', op: 'eq', value: 'burger' }],
      },
      then: [{ type: 'show', groupId: '2' }],
    },
    {
      type: 'expr',
      when: {
        and: [{ groupId: '1', op: 'eq', value: 'pizza' }],
      },
      then: [{ type: 'show', groupId: '3' }],
    },
  ];

  return (
    <SelectorGroup
      dataSource={dataSource}
      linkageRules={linkageRules}
      value={values}
      onChange={setValues}
    />
  );
};
```

### 选项联动

一个组的选择影响另一个组的可选项。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

const SelectorGroup = Selector.Group;

export default () => {
  const [values, setValues] = useState({});

  const dataSource = [
    {
      id: 1,
      title: '饮品',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'value', label: 'title' },
      dataSource: [
        { id: 1, title: 'Coffee', value: 'coffee' },
        { id: 2, title: 'Tea', value: 'tea' },
      ],
    },
    {
      id: 2,
      title: '加料',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'value', label: 'title' },
      dataSource: [
        { id: 1, title: 'Milk', value: 'milk' },
        { id: 2, title: 'Sugar', value: 'sugar' },
        { id: 3, title: 'Lemon', value: 'lemon' },
        { id: 4, title: 'Honey', value: 'honey' },
      ],
    },
  ];

  const linkageRules = [
    {
      type: 'expr',
      when: { and: [{ groupId: '1', op: 'eq', value: 'coffee' }] },
      then: [
        {
          type: 'allowOnly',
          groupId: '2',
          values: ['milk', 'sugar'],
          tip: '加料仅允许 Milk/Sugar',
        },
      ],
    },
    {
      type: 'expr',
      when: { and: [{ groupId: '1', op: 'eq', value: 'tea' }] },
      then: [
        {
          type: 'allowOnly',
          groupId: '2',
          values: ['lemon', 'honey'],
          tip: '加料仅允许 Lemon/Honey',
        },
      ],
    },
  ];

  return (
    <SelectorGroup
      dataSource={dataSource}
      linkageRules={linkageRules}
      allowedValuesPolicy="strict"
      value={values}
      onChange={setValues}
    />
  );
};
```

### 标签页模式

启用标签页导航，方便在多个分组间切换。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

const SelectorGroup = Selector.Group;

export default () => {
  const [values, setValues] = useState({});

  const dataSource = [
    {
      id: 1,
      title: '主菜',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '汉堡' },
        { id: 2, title: '披萨' },
      ],
    },
    {
      id: 2,
      title: '饮品',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '可乐' },
        { id: 2, title: '雪碧' },
      ],
    },
    {
      id: 3,
      title: '小食',
      mode: 'multiple',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '薯条' },
        { id: 2, title: '鸡块' },
      ],
    },
  ];

  return (
    <SelectorGroup
      dataSource={dataSource}
      value={values}
      onChange={setValues}
      tabProps={{ visible: true }}
    />
  );
};
```

### 主题

自定义选择器的主题颜色。

```tsx
import React, { useState } from 'react';
import { Selector } from '@pisell/private-materials';

const SelectorGroup = Selector.Group;

export default () => {
  const [values, setValues] = useState({});
  const [colorPrimary, setColorPrimary] = useState('#1890FF');

  const dataSource = [
    {
      id: 1,
      title: '主菜',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '汉堡' },
        { id: 2, title: '披萨' },
      ],
      theme: { token: { colorPrimary } }
    },
    {
      id: 2,
      title: '饮品',
      mode: 'single',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '可乐' },
        { id: 2, title: '雪碧' },
      ],
      theme: { token: { colorPrimary } }
    },
    {
      id: 3,
      title: '小食',
      mode: 'multiple',
      valueType: 'primitive',
      fieldNames: { value: 'id', label: 'title' },
      dataSource: [
        { id: 1, title: '薯条' },
        { id: 2, title: '鸡块' },
      ],
      theme: { token: { colorPrimary } }
    },
  ];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <input
        type="color"
        value={colorPrimary}
        onChange={(e) => setColorPrimary(e.target.value)}
        style={{ width: 48, height: 32, padding: 0, border: 'none' }}
      />
      <SelectorGroup
        dataSource={dataSource}
        value={values}
        onChange={setValues}
        theme={{ token: { colorPrimary } }}
      />
    </div>
  );
};
```

## API

### Selector

| 参数           | 说明                 | 类型                                                 | 默认值         |
| -------------- | -------------------- | ---------------------------------------------------- | -------------- |
| id             | 选择器唯一标识       | `string \| number`                                   | -              |
| title          | 选择器标题           | `string`                                             | -              |
| mode           | 选择模式             | `'single' \| 'multiple'`                             | `'single'`     |
| valueType      | 值类型               | `'primitive' \| 'object'`                            | `'primitive'`  |
| variant        | 显示变体             | `'default' \| 'card' \| 'select' \| 'media'`         | `'default'`    |
| preset         | 预设配置（快速布局） | `PresetConfig`                                       | -              |
| dataSource     | 选项数据源           | `OptionItem[]`                                       | `[]`           |
| value          | 当前值（受控）       | `SelectionValue`                                     | -              |
| defaultValue   | 默认值（非受控）     | `SelectionValue`                                     | -              |
| onChange       | 值变化回调           | `(value: SelectionValue) => void`                    | -              |
| onClear        | 清空回调             | `() => void`                                         | -              |
| disabled       | 是否禁用             | `boolean`                                            | `false`        |
| fieldNames     | 自定义字段名         | `{ label?: string; value?: string; cover?: string }` | -              |
| layout         | 布局配置（高级）     | `LayoutConfig`                                       | -              |
| itemLayout     | 选项布局方向         | `'horizontal' \| 'vertical'`                         | `'horizontal'` |
| itemProps      | 选项配置             | `ItemProps`                                          | -              |
| titleProps     | 标题配置             | `TitleProps`                                         | -              |
| ruleConfig     | 校验规则配置         | `RuleConfig`                                         | -              |
| renderItem     | 自定义选项渲染       | `(props: RenderItemProps) => ReactNode`              | -              |
| indicatorProps | 指示器配置           | `IndicatorProps`                                     | -              |
| showStepper    | 是否显示数量选择     | `true \| false \| 'auto'`                            | `'auto'`       |
| stepperProps   | 数量选择器配置       | `StepperProps`                                       | -              |
| className      | 自定义类名           | `string`                                             | -              |
| style          | 自定义样式           | `CSSProperties`                                      | -              |

### SelectorGroup

| 参数                | 说明               | 类型                                               | 默认值               |
| ------------------- | ------------------ | -------------------------------------------------- | -------------------- |
| dataSource          | 选择器组数据源     | `GroupItem[]`                                      | `[]`                 |
| linkageRules        | 联动规则           | `ExprRule[] \| Record<string, any>`                | -                    |
| allowedValuesPolicy | 允许值策略         | `'relaxed' \| 'strict'`                            | `'strict'`           |
| preserve            | 是否保留隐藏组的值 | `boolean`                                          | `false`              |
| value               | 当前值（受控）     | `Record<string, SelectionValue>`                   | -                    |
| defaultValue        | 默认值（非受控）   | `Record<string, SelectionValue>`                   | -                    |
| onChange            | 值变化回调         | `(values: Record<string, SelectionValue>) => void` | -                    |
| tabProps            | 标签页配置         | `{ visible?: boolean }`                            | `{ visible: false }` |
| customScrollParent  | 自定义滚动容器     | `HTMLElement \| string`                            | -                    |
| className           | 自定义类名         | `string`                                           | -                    |
| style               | 自定义样式         | `CSSProperties`                                    | -                    |

### PresetConfig

| 参数    | 说明                                                          | 类型                              | 默认值 |
| ------- | ------------------------------------------------------------- | --------------------------------- | ------ |
| variant | 预设变体（不同 variant 支持的 preset 数量不同，详见下方说明） | `'1' \| '2' \| '3' \| '4' \| '5'` | -      |

**支持的 Preset Variant：**

- `default`: 支持 variant '1', '2', '3', '4'
- `card`: 支持 variant '1', '2', '3', '4', '5'
- `media`: 支持 variant '1', '2'（自动应用 filled 指示器）
- `select`: 仅支持 variant '1'（下拉选择器）

### LayoutConfig

| 参数           | 说明                                  | 类型                                                                | 默认值 |
| -------------- | ------------------------------------- | ------------------------------------------------------------------- | ------ |
| type           | 布局类型                              | `'antdGrid' \| 'custom'`                                            | -      |
| containerStyle | 自定义容器样式（推荐使用，更灵活）    | `React.CSSProperties`                                               | -      |
| gutter         | 子元素间距（可转换为 gap）            | `number \| object \| Array<number>`                                 | `0`    |
| columns        | 网格列数（仅 type='antdGrid' 时生效） | `number`                                                            | -      |
| align          | 垂直对齐（仅 type='antdGrid' 时生效） | `'top' \| 'middle' \| 'bottom' \| 'stretch'`                        | -      |
| justify        | 水平对齐（仅 type='antdGrid' 时生效） | `'start' \| 'end' \| 'center' \| 'space-between' \| 'space-around'` | -      |
| wrap           | 是否换行（仅 type='antdGrid' 时生效） | `boolean`                                                           | `true` |
| colConfig      | 列配置（仅 type='antdGrid' 时生效）   | `object`（如 `{ xs: 24, sm: 12, md: 8 }`）                          | -      |

### OptionItem

| 参数       | 说明               | 类型                             | 默认值  |
| ---------- | ------------------ | -------------------------------- | ------- |
| id         | 选项唯一标识       | `number \| string`               | -       |
| title      | 选项标题           | `string`                         | -       |
| label      | 选项标签           | `string`                         | -       |
| value      | 选项值             | `number \| string`               | -       |
| cover      | 封面图片           | `string`                         | -       |
| disabled   | 是否禁用           | `boolean`                        | `false` |
| groups     | 选项组列表（预留） | `GroupItem[]`                    | -       |
| ruleConfig | 选项级别的规则配置 | `{ min?: number; max?: number }` | -       |

### RuleConfig

| 参数            | 说明         | 类型                                       | 默认值  |
| --------------- | ------------ | ------------------------------------------ | ------- |
| required        | 是否必填     | `0 \| 1`                                   | `0`     |
| autoValidate    | 是否自动校验 | `boolean`                                  | `false` |
| min             | 最小选择数量 | `number`                                   | -       |
| max             | 最大选择数量 | `number`                                   | -       |
| mutex           | 互斥组配置   | `Array<Array<OptionKey>>`                  | -       |
| customValidator | 自定义校验器 | `(value: SelectionValue) => Promise<void>` | -       |

### RenderItemProps（自定义渲染参数）

| 参数            | 说明           | 类型             |
| --------------- | -------------- | ---------------- |
| dataSource      | 选项数据       | `OptionItem`     |
| actions         | 操作对象       | `any`            |
| optionItemValue | 选项当前值     | `SelectionValue` |
| indicator       | 指示器节点     | `ReactNode`      |
| numberSelector  | 数量选择器节点 | `ReactNode`      |
| values          | 当前所有值     | `SelectionValue` |
| quantityInfo    | 数量信息       | `QuantityInfo`   |

### ItemProps（选项配置）

| 参数          | 说明           | 类型                                                                          | 默认值         |
| ------------- | -------------- | ----------------------------------------------------------------------------- | -------------- |
| layout        | 布局方向       | `'horizontal' \| 'vertical'`                                                  | `'horizontal'` |
| renderContent | 自定义内容渲染 | `(props: { dataSource: OptionItem }) => ReactNode`                            | -              |
| styles        | 自定义样式     | `{ container?: CSSProperties; cover?: CSSProperties; label?: CSSProperties }` | -              |

### IndicatorProps（指示器配置）

| 参数    | 说明           | 类型                                                                                               | 默认值       |
| ------- | -------------- | -------------------------------------------------------------------------------------------------- | ------------ |
| show    | 是否展示指示器 | `boolean`                                                                                          | `true`       |
| variant | 指示器样式变体 | `'outlined' \| 'filled'`                                                                           | `'outlined'` |
| render  | 自定义指示器   | `(props: { option: OptionItem; selected: boolean; disabled: boolean; actions: any }) => ReactNode` | -            |

### StepperProps（数量选择器配置）

| 参数  | 说明 | 类型                             | 默认值 |
| ----- | ---- | -------------------------------- | ------ |
| size  | 尺寸 | `'small' \| 'middle' \| 'large'` | -      |
| shape | 形状 | `'round' \| 'square'`            | -      |

### TitleProps

| 参数        | 说明           | 类型                                                                       | 默认值 |
| ----------- | -------------- | -------------------------------------------------------------------------- | ------ |
| visible     | 是否显示标题   | `boolean`                                                                  | `true` |
| style       | 标题容器样式   | `CSSProperties`                                                            | -      |
| title       | 标题文本配置   | `{ visible?: boolean; text?: ReactNode; style?: CSSProperties }`           | -      |
| icon        | 图标配置       | `{ visible?: boolean; icon?: ReactNode; style?: CSSProperties }`           | -      |
| tip         | 提示文本配置   | `{ visible?: boolean; text?: ReactNode; style?: CSSProperties }`           | -      |
| renderExtra | 自定义额外内容 | `(props: { dataSource: OptionItem; values: SelectionValue }) => ReactNode` | -      |

### LinkageRule（联动规则）

| 参数           | 说明          | 类型                                      | 默认值   |
| -------------- | ------------- | ----------------------------------------- | -------- |
| type           | 规则类型      | `'expr'`                                  | `'expr'` |
| when           | 触发条件      | `{ and?: Condition[]; or?: Condition[] }` | -        |
| then           | 执行动作      | `Action[]`                                | -        |
| elseThen       | else 分支动作 | `Action[]`                                | -        |
| priority       | 优先级        | `number`                                  | `0`      |
| stopAfterApply | 是否短路      | `boolean`                                 | `false`  |

#### Condition（条件）

| 参数    | 说明    | 类型                                                      |
| ------- | ------- | --------------------------------------------------------- |
| groupId | 分组 ID | `string`                                                  |
| op      | 操作符  | `'eq' \| 'ne' \| 'in' \| 'notIn' \| 'hasAny' \| 'hasAll'` |
| value   | 比较值  | `any \| any[]`                                            |

#### Action（动作）

**显示/隐藏分组：**

```typescript
{
  type: 'show' | 'hide';
  groupId: string;
}
```

**限制可选项：**

```typescript
{
  type: 'allowOnly';
  groupId: string;
  values: any[];
  message?: string;  // 校验失败提示
  tip?: string;      // 标题提示文本
}
```

**必选指定项之一：**

```typescript
{
  type: 'requireOneOf';
  groupId: string;
  values: any[];
  message?: string;  // 校验失败提示
  tip?: string;      // 标题提示文本
}
```

### SelectionValue（值类型）

根据 `mode` 和 `valueType` 的不同，值类型有以下几种形式：

**单选 + primitive：**

```typescript
value: string | number;
// 例如：'burger' 或 1
```

**单选 + object：**

```typescript
value: {
  value: string | number;
  quantity?: number;
  [key: string]: any;
}
// 例如：{ value: 'burger', quantity: 2 }
```

**多选 + primitive：**

```typescript
value: Array<string | number>;
// 例如：['lettuce', 'tomato', 'cheese'] 或 [1, 2, 3]
```

**多选 + object：**

```typescript
value: Array<{
  value: string | number;
  quantity?: number;
  [key: string]: any;
}>;
// 例如：[
//   { value: 'lettuce', quantity: 1 },
//   { value: 'tomato', quantity: 2 }
// ]
```

### Ref 方法

#### Selector Ref

| 方法      | 说明         | 类型                  |
| --------- | ------------ | --------------------- |
| validate  | 执行校验     | `() => Promise<void>` |
| getErrors | 获取错误信息 | `() => any[]`         |
| reset     | 重置为默认值 | `() => void`          |
| clear     | 清空值       | `() => void`          |

#### SelectorGroup Ref

| 方法      | 说明           | 类型                                                          |
| --------- | -------------- | ------------------------------------------------------------- |
| getValues | 获取所有值     | `(includeHidden?: boolean) => Record<string, SelectionValue>` |
| setValues | 设置所有值     | `(values: Record<string, SelectionValue>) => void`            |
| validate  | 执行所有组校验 | `() => Promise<Record<string, never>>`                        |
| reset     | 重置所有组     | `() => void`                                                  |
| clear     | 清空所有组     | `() => void`                                                  |

## 注意事项

1. **Preset vs Layout**：
   - 使用 `preset` 时无需配置 `layout`，系统会自动应用预设布局
   - 如果同时指定 `preset` 和 `layout`，`layout` 的配置优先级更高
   - 建议非专业用户使用 `preset`，专业开发者根据需要使用 `layout` 精确控制

2. **valueType 选择**：当需要记录数量信息时，使用 `valueType="object"`；否则使用 `valueType="primitive"` 可获得更简洁的数据结构。

3. **fieldNames 配置**：确保 `fieldNames` 中的字段名与 `dataSource` 中的实际字段名一致。

4. **联动规则优先级**：多条规则同时生效时，`priority` 值越大优先级越高。

5. **allowedValuesPolicy**：
   - `strict` 模式：当选项被禁用时，会自动清除该选项的已选状态
   - `relaxed` 模式：保留已选状态，但选项会被禁用

6. **性能优化**：大量选项时建议使用虚拟滚动或分组展示。

7. **校验时机**：设置 `autoValidate: true` 后会在值变化时自动校验，否则需要手动调用 `validate()` 方法。

8. **Preset 自动应用的 indicator 样式**：
   - `media` variant 的所有 preset 会自动应用 `filled` 风格的指示器
   - `card` variant 的 preset '2' 会自动应用 `filled` 风格的指示器
