npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kne/super-select

v0.1.51

Published

React 复杂信息选择组件库,提供列表、表格、树形等多种选择模式,支持单选/多选、搜索、全选等功能

Readme

super-select

描述

React 复杂信息选择组件库,提供列表、表格、树形等多种选择模式,支持单选/多选、搜索、全选等功能

关键词

react, select, picker, multiselect, tree-select, table-select, antd, form, dropdown, searchable, i18n

安装

npm i --save @kne/super-select

概述

一个功能强大的 React 组件库,专门用于处理复杂的信息选择场景。提供了一系列灵活且可组合的组件,使得在 React 应用中实现复杂的选择功能变得简单直观。

主要功能

  • 支持多种选择模式(单选、多选)
  • 支持下拉框和弹窗两种展示模式
  • 提供灵活的列表和表格展示方式
  • 内置标签式选中项展示
  • 支持全选/反选功能
  • 内置国际化支持(中文和英文)
  • 自定义样式支持(基于 CSS Modules)
  • 标签溢出处理:单选文本省略、多选标签自动折叠显示 +N

组件列表

| 组件名称 | 功能描述 | | --------------- | ------------------------------------------------------- | | SelectInput | 基础选择输入组件,用于自定义构建其他选择组件的核心基础 | | SelectList | 列表选择组件,适用于常规列表选择场景 | | SelectTableList | 表格形式选择组件,支持多列数据与 tree/treeList 树形选择 | | SelectedAll | 全选功能组件,提供一键选择/取消选择 | | SelectTree | 树形选择组件,适用于层级数据 | | SelectedTagList | 已选项标签列表组件 | | SelectCascader | 级联选择组件,支持父子关联、搜索过滤 |

快速选择指南

| 需求 | 推荐组件 | | ---------------- | ----------------------------------------- | | 自定义选择组件 | SelectInput | | 简单列表选择 | SelectList | | 需要展示多列数据 | SelectTableList | | 表格内树形选择 | SelectTableList(dataType=tree/treeList) | | 层级数据选择 | SelectTree 或 SelectCascader | | 全选/反选功能 | SelectedAll | | 已选项标签展示 | SelectedTagList |

快速开始

import { SelectInput, SelectList, SelectCascader } from '@kne/super-select';

// 自定义选择组件
<SelectInput placeholder="请选择" onChange={handleChange}>
  {(props) => <CustomDropdown {...props} />}
</SelectInput>

// 级联选择
<SelectCascader options={cascadeData} onChange={handleChange} />

示例

示例样式

.max-width-150 {
  max-width: 150px;
}

示例代码

  • SelectInput 基础组件
  • 基础选择输入组件,展示尺寸、多选、弹窗模式、前后缀等核心功能
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { SelectInput } = _SuperSelect;
const { Space, Flex, Divider, Button, Tag, Switch } = antd;
const { useState } = React;

// 基础示例:展示基本使用和尺寸
const BasicExample = ({ isPopup }) => {
  return (
    <Flex vertical gap={12}>
      <Flex gap={8} align="center">
        <span>基础使用:</span>
        <SelectInput isPopup={isPopup} placeholder="请选择" style={{ width: 200 }} />
        <SelectInput isPopup={isPopup} placeholder="禁用状态" disabled style={{ width: 200 }} />
      </Flex>
      <Flex gap={8} align="center">
        <span>尺寸:</span>
        <SelectInput isPopup={isPopup} size="small" placeholder="小尺寸" style={{ width: 120 }} />
        <SelectInput isPopup={isPopup} size="default" placeholder="默认尺寸" style={{ width: 140 }} />
        <SelectInput isPopup={isPopup} size="large" placeholder="大尺寸" style={{ width: 160 }} />
      </Flex>
    </Flex>
  );
};

// 多选示例:展示多选和标签显示
const MultiSelectExample = ({ isPopup }) => {
  const [value, setValue] = useState([
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue' }
  ]);

  return (
    <Flex vertical gap={12}>
      <Flex gap={8} align="center">
        <span>多选模式:</span>
        <SelectInput
          value={value}
          onChange={setValue}
          isPopup={isPopup}
          placeholder="请选择技术栈"
          style={{ width: 300 }}
        />
      </Flex>
      <Flex gap={8} align="center">
        <span>带数量限制:</span>
        <SelectInput
          defaultValue={[
            { value: 1, label: '选项一' },
            { value: 2, label: '选项二' }
          ]}
          isPopup={isPopup}
          maxLength={3}
          placeholder="最多选择3项"
          style={{ width: 300 }}
        />
      </Flex>
    </Flex>
  );
};

// 自定义前后缀示例
const PrefixSuffixExample = ({ isPopup }) => {
  const [value, setValue] = useState([
    { value: 'tech', label: '技术研发部' }
  ]);

  return (
    <Flex vertical gap={12}>
      <Flex gap={12} align="center">
        <SelectInput
          value={value}
          onChange={setValue}
          isPopup={isPopup}
          prefix={
            <Tag color="blue" style={{ margin: 0, borderRadius: 4 }}>
              部门
            </Tag>
          }
          placeholder="请选择部门"
          style={{ width: 240 }}
        />
        <SelectInput
          defaultValue={[{ value: 'project', label: '项目A' }]}
          isPopup={isPopup}
          suffix={
            <Button type="primary" size="small" style={{ fontSize: 12 }}>
              详情
            </Button>
          }
          placeholder="请选择项目"
          style={{ width: 240 }}
        />
      </Flex>
      <Flex gap={12} align="center">
        <SelectInput
          defaultValue={[{ value: 'user1', label: '张三' }]}
          isPopup={isPopup}
          prefix={
            <span style={{ 
              color: '#1677ff', 
              fontWeight: 500,
              fontSize: 13
            }}>
              负责人:
            </span>
          }
          placeholder="请选择负责人"
          style={{ width: 220 }}
        />
        <SelectInput
          size="large"
          isPopup={isPopup}
          defaultValue={[{ value: 'pending', label: '待处理' }]}
          suffix={
            <Tag color="orange" style={{ margin: 0 }}>
              3条待办
            </Tag>
          }
          placeholder="请选择状态"
          style={{ width: 260 }}
        />
      </Flex>
    </Flex>
  );
};

const BaseExample = () => {
  const [isPopup, setIsPopup] = useState(true);

  return (
    <Flex vertical gap={24}>
      <Flex align="center" gap={12}>
        <span>展示模式:</span>
        <Switch
          checked={isPopup}
          onChange={setIsPopup}
          checkedChildren="下拉"
          unCheckedChildren="弹窗"
        />
        <span style={{ color: '#666', fontSize: 12 }}>
          {isPopup ? '点击输入框展开下拉菜单' : '点击输入框打开弹窗'}
        </span>
      </Flex>
      <Divider />
      <BasicExample isPopup={isPopup} />
      <Divider />
      <MultiSelectExample isPopup={isPopup} />
      <Divider />
      <PrefixSuffixExample isPopup={isPopup} />
    </Flex>
  );
};

render(<BaseExample />);
  • SelectInput 边界情况测试
  • 测试超多选项(100项)、超长Label文本、大量已选项展示等边界场景
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { SelectInput } = _SuperSelect;
const { Flex, Tag } = antd;
const { useState } = React;

// 超多选项测试示例(100项)
const ManyOptionsExample = () => {
  const manyOptions = Array.from({ length: 100 }, (_, i) => ({
    value: &#96;user_${i + 1}&#96;,
    label: &#96;用户${i + 1}&#96;
  }));
  
  // 直接预选10项测试
  const [value, setValue] = useState(manyOptions.slice(0, 10));

  return (
    <Flex vertical gap={12}>
      <span>超多选项显示测试(已选10项):</span>
      <SelectInput
        value={value}
        onChange={setValue}
        placeholder="请选择用户"
        style={{ width: 400 }}
      >
        {() => <div style={{ padding: 12 }}>下拉内容</div>}
      </SelectInput>
      <Tag color="blue">已选择 {value.length} 项</Tag>
    </Flex>
  );
};

// 超长Label测试示例
const LongLabelExample = () => {
  const longLabelOptions = [
    { value: 'dept-1', label: '人工智能与机器学习应用技术研发中心' },
    { value: 'dept-2', label: '自然语言处理与智能对话系统研发组' },
    { value: 'dept-3', label: '大语言模型训练与优化专项小组' },
    { value: 'dept-4', label: '云计算与大数据平台架构设计及实施运维中心' },
    { value: 'dept-5', label: '网络安全与数据隐私保护技术保障中心' },
    { value: 'dept-6', label: '物联网设备智能互联与边缘计算技术研发中心' },
    { value: 'dept-7', label: '智能客服机器人产品研发团队-多模态交互技术组' },
    { value: 'dept-8', label: '金融科技创新应用与区块链技术研发实验室' }
  ];
  
  const [value, setValue] = useState(longLabelOptions);

  return (
    <Flex vertical gap={12}>
      <span>超长Label文本省略测试:</span>
      <SelectInput
        value={value}
        onChange={setValue}
        placeholder="请选择部门"
        style={{ width: 280 }}
      >
        {() => <div style={{ padding: 12 }}>下拉内容</div>}
      </SelectInput>
    </Flex>
  );
};

// 单选模式下超长Label测试
const SingleLongLabelExample = () => {
  const [value, setValue] = useState({ 
    value: 1, 
    label: '人工智能与机器学习应用技术研发中心-自然语言处理与智能对话系统研发组-大语言模型训练与优化专项小组' 
  });

  return (
    <Flex vertical gap={12}>
      <span>单选模式 - 超长Label:</span>
      <SelectInput
        single
        value={value}
        onChange={setValue}
        placeholder="请选择部门"
        style={{ width: 240 }}
      >
        {() => <div style={{ padding: 12 }}>下拉内容</div>}
      </SelectInput>
      {value && <Tag color="green">已选:{value.label}</Tag>}
    </Flex>
  );
};

// 大量已选项展示测试
const ManySelectedExample = () => {
  const [value, setValue] = useState(
    Array.from({ length: 20 }, (_, i) => ({
      value: &#96;item_${i + 1}&#96;,
      label: &#96;选项${i + 1}&#96;
    }))
  );

  return (
    <Flex vertical gap={12}>
      <span>大量已选项展示(默认已选20项):</span>
      <SelectInput
        value={value}
        onChange={setValue}
        placeholder="请选择"
        style={{ width: 400 }}
      >
        {() => <div style={{ padding: 12 }}>下拉内容</div>}
      </SelectInput>
    </Flex>
  );
};

const BaseExample = () => {
  return (
    <Flex vertical gap={24}>
      <ManyOptionsExample />
      <LongLabelExample />
      <SingleLongLabelExample />
      <ManySelectedExample />
    </Flex>
  );
};

render(<BaseExample />);
  • SuperSelect 列表选择
  • 通用列表选择组件,支持单选/多选、搜索、全选、数量限制、弹窗模式等功能
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { default: SuperSelect } = _SuperSelect;
const { Space, Button, Flex, Divider, Tag, Switch } = antd;
const { useState } = React;

// 模拟部门数据
const departmentOptions = [
  { value: 'tech', label: '技术研发部', disabled: false },
  { value: 'product', label: '产品设计部', disabled: false },
  { value: 'operation', label: '运营管理部', disabled: false },
  { value: 'hr', label: '人力资源部', disabled: false },
  { value: 'finance', label: '财务部', disabled: true },
  { value: 'marketing', label: '市场营销部', disabled: false }
];

// 模拟用户数据
const userOptions = Array.from({ length: 30 }).map((_, index) => ({
  value: &#96;user_${index + 1}&#96;,
  label: &#96;用户${index + 1}&#96;,
  email: &#96;user${index + 1}@company.com&#96;,
  department: departmentOptions[index % departmentOptions.length].label,
  disabled: index === 5
}));

// 基础列表选择
const BasicListExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>多选列表:</span>
      <SuperSelect
        options={departmentOptions}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择部门"
        style={{ width: 280 }}
      />
      {value.length > 0 && (
        <div>已选:{value.map(item => item.label).join('、')}</div>
      )}
    </Flex>
  );
};

// 单选列表
const SingleSelectExample = ({ isPopup }) => {
  const [value, setValue] = useState(null);

  return (
    <Flex vertical gap={8}>
      <span>单选列表:</span>
      <SuperSelect
        single
        options={userOptions.slice(0, 10)}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择负责人"
        style={{ width: 280 }}
      />
      {value && <div>已选:{value.label}</div>}
    </Flex>
  );
};

// 带搜索的选择
const SearchableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>带搜索功能:</span>
      <SuperSelect
        options={userOptions}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="搜索并选择用户"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return (
            item.label.toLowerCase().includes(keyword) ||
            item.email.toLowerCase().includes(keyword)
          );
        }}
        style={{ width: 320 }}
      />
    </Flex>
  );
};

// 全选功能
const SelectAllExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>支持全选:</span>
      <SuperSelect
        allowSelectedAll
        options={departmentOptions.filter(item => !item.disabled)}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择部门(支持全选)"
        style={{ width: 280 }}
      />
    </Flex>
  );
};

// 带数量限制
const MaxLimitExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>最多选择3项:</span>
      <SuperSelect
        options={userOptions.slice(0, 10)}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        maxLength={3}
        placeholder="请选择(最多3项)"
        style={{ width: 320 }}
      />
      <Tag color={value.length >= 3 ? 'red' : 'blue'}>
        已选择 {value.length}/3 项
      </Tag>
    </Flex>
  );
};

// 自定义渲染
const CustomRenderExample = () => {
  return (
    <Flex vertical gap={8}>
      <span>自定义输入框渲染:</span>
      <SuperSelect
        options={departmentOptions}
        inputRender={(props, context) => {
          const { value } = context;
          return (
            <Button type="primary" {...props}>
              {value.length > 0 ? &#96;已选择 ${value.length} 项&#96; : '点击选择部门'}
            </Button>
          );
        }}
      />
    </Flex>
  );
};

const BaseExample = () => {
  const [isPopup, setIsPopup] = useState(true);

  return (
    <Flex vertical gap={24}>
      <Flex align="center" gap={12}>
        <span>展示模式:</span>
        <Switch
          checked={isPopup}
          onChange={setIsPopup}
          checkedChildren="下拉"
          unCheckedChildren="弹窗"
        />
        <span style={{ color: '#666', fontSize: 12 }}>
          {isPopup ? '点击输入框展开下拉菜单' : '点击输入框打开弹窗'}
        </span>
      </Flex>
      <Divider />
      <BasicListExample isPopup={isPopup} />
      <Divider />
      <SingleSelectExample isPopup={isPopup} />
      <Divider />
      <SearchableExample isPopup={isPopup} />
      <Divider />
      <SelectAllExample isPopup={isPopup} />
      <Divider />
      <MaxLimitExample isPopup={isPopup} />
      <Divider />
      <CustomRenderExample />
    </Flex>
  );
};

render(<BaseExample />);
  • SelectTableList 表格选择
  • 表格形式的选择组件,适合复杂数据的展示和选择,支持自定义列、搜索、单选/多选、tree/treeList 树形、checkRelation、懒加载、renderMobile 自定义移动端卡片等
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { SelectTableList, mergeTreeChildren } = _SuperSelect;
const { Space, Button, Flex, Divider, Tag, Avatar, Switch, Checkbox, Radio } = antd;
const { useState } = React;

// 模拟员工数据
const employeeOptions = Array.from({ length: 25 }).map((_, index) => ({
  id: &#96;emp_${index + 1}&#96;,
  name: &#96;员工${index + 1}&#96;,
  email: &#96;employee${index + 1}@company.com&#96;,
  department: ['技术研发部', '产品设计部', '运营部', '市场部'][index % 4],
  position: ['工程师', '设计师', '经理', '专员'][index % 4],
  status: index === 3 ? 'inactive' : 'active',
  joinDate: &#96;2023-${String((index % 12) + 1).padStart(2, '0')}-15&#96;
}));

// 员工列表列配置
const employeeColumns = [
  {
    name: 'name',
    title: '姓名',
    span: 6,
    getValueOf: item => (
      <Flex align="center" gap={8}>
        <Avatar size="small" style={{ backgroundColor: '#1677ff' }}>
          {item.name.slice(-2)}
        </Avatar>
        <span>{item.name}</span>
      </Flex>
    )
  },
  {
    name: 'department',
    title: '部门',
    span: 6
  },
  {
    name: 'position',
    title: '职位',
    span: 4
  },
  {
    name: 'email',
    title: '邮箱',
    span: 6,
    getValueOf: item => <span style={{ color: '#666', fontSize: 12 }}>{item.email}</span>
  },
  {
    name: 'options',
    title: '操作',
    span: 2,
    getValueOf: (item, { context }) => {
      return (
        <Button
          type="link"
          size="small"
          danger
          disabled={item.status === 'inactive'}
          onClick={e => {
            e.stopPropagation();
            console.log('删除员工:', item.name);
          }}
        >
          移除
        </Button>
      );
    }
  }
];

// 产品数据
const productOptions = Array.from({ length: 20 }).map((_, index) => ({
  id: &#96;prod_${index + 1}&#96;,
  productName: &#96;产品${index + 1}&#96;,
  category: ['电子产品', '服装', '食品', '家居'][index % 4],
  price: Math.floor(Math.random() * 1000) + 100,
  stock: Math.floor(Math.random() * 500),
  status: index === 5 ? '下架' : '在售'
}));

const productColumns = [
  {
    name: 'productName',
    title: '产品名称',
    span: 6
  },
  {
    name: 'category',
    title: '分类',
    span: 4,
    getValueOf: item => <Tag color="blue">{item.category}</Tag>
  },
  {
    name: 'price',
    title: '价格',
    span: 4,
    getValueOf: item => &#96;¥${item.price}&#96;
  },
  {
    name: 'stock',
    title: '库存',
    span: 4,
    getValueOf: item => <span style={{ color: item.stock < 50 ? 'red' : 'green' }}>{item.stock}</span>
  },
  {
    name: 'status',
    title: '状态',
    span: 4,
    getValueOf: item => <Tag color={item.status === '在售' ? 'success' : 'default'}>{item.status}</Tag>
  }
];

// 基础表格选择
const BasicTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>多选表格:</span>
      <SelectTableList options={employeeOptions} columns={employeeColumns} valueKey="id" labelKey="name" value={value} onChange={setValue} isPopup={isPopup} placeholder="请选择员工" style={{ width: 600 }} />
      {value.length > 0 && (
        <div>
          已选 {value.length} 人:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

// 单选表格
const SingleTableExample = ({ isPopup }) => {
  const [value, setValue] = useState(null);

  return (
    <Flex vertical gap={8}>
      <span>单选表格:</span>
      <SelectTableList single options={productOptions} columns={productColumns} valueKey="id" labelKey="productName" value={value} onChange={setValue} isPopup={isPopup} placeholder="请选择产品" style={{ width: 600 }} />
      {value && <div>已选:{value.productName}</div>}
    </Flex>
  );
};

// 带搜索的表格选择
const SearchableTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>带搜索功能:</span>
      <SelectTableList
        options={employeeOptions}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="搜索姓名、邮箱或部门"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return item.name.toLowerCase().includes(keyword) || item.email.toLowerCase().includes(keyword) || item.department.toLowerCase().includes(keyword);
        }}
        style={{ width: 600 }}
      />
    </Flex>
  );
};

const remoteSearchListFilter = { language: 'zh-CN' };

// 模拟分页 loader:根据 currentPage/perPage 切片,保留 filter
const makePaginatedLoader = (allData, setLastRequest) => request => {
  const params = request?.params || {};
  const snapshot = { params, data: request?.data || {} };
  setTimeout(() => setLastRequest(snapshot), 0);
  const keyword = (params.filter?.keyword || '').toLowerCase();
  const filtered = allData.filter(item => {
    if (!keyword) return true;
    return item.name.toLowerCase().includes(keyword) || item.email.toLowerCase().includes(keyword) || item.department.toLowerCase().includes(keyword);
  });
  const currentPage = params.currentPage || 1;
  const perPage = params.perPage || 5;
  const start = (currentPage - 1) * perPage;
  const pageData = filtered.slice(start, start + perPage);
  return { pageData, totalCount: filtered.length };
};

// 远程搜索 + 分页器(默认 pagination.open=true)
const RemoteSearchTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);
  const [lastRequest, setLastRequest] = useState(null);
  const api = React.useMemo(
    () => ({
      params: { filter: remoteSearchListFilter, perPage: 5, currentPage: 1 },
      loader: makePaginatedLoader(employeeOptions, setLastRequest)
    }),
    []
  );

  return (
    <Flex vertical gap={8}>
      <span>远程搜索 + 分页器(验证翻页 filter 不丢):</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>
        每页 5 条,共 25 条。翻页后观察下方请求参数:params.filter.language 应始终为 zh-CN;搜索后翻页 keyword 也不丢。
      </div>
      <SelectTableList
        api={api}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="搜索姓名、邮箱或部门"
        getSearchProps={({ searchText }) => ({
          filter: Object.assign({}, remoteSearchListFilter, searchText ? { keyword: searchText } : {})
        })}
        pagination={{ paramsType: 'params' }}
        style={{ width: 600 }}
      />
      {lastRequest ? (
        <pre style={{ margin: 0, fontSize: 12, background: '#f5f5f5', padding: 8, borderRadius: 4, overflow: 'auto' }}>{JSON.stringify(lastRequest, null, 2)}</pre>
      ) : null}
    </Flex>
  );
};

// 远程搜索 + 下拉加载(pagination.open=false)
const RemoteSearchLoadMoreExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);
  const [lastRequest, setLastRequest] = useState(null);
  const api = React.useMemo(
    () => ({
      params: { filter: remoteSearchListFilter, perPage: 5, currentPage: 1 },
      loader: makePaginatedLoader(employeeOptions, setLastRequest)
    }),
    []
  );

  return (
    <Flex vertical gap={8}>
      <span>远程搜索 + 下拉加载(验证 open=false 自动 loadMore):</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>
        每页 5 条,无分页器。滚动到底部自动加载下一页,数据追加显示。翻页时 filter.language 不丢。
      </div>
      <SelectTableList
        api={api}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="搜索姓名、邮箱或部门"
        getSearchProps={({ searchText }) => ({
          filter: Object.assign({}, remoteSearchListFilter, searchText ? { keyword: searchText } : {})
        })}
        pagination={{ open: false, paramsType: 'params' }}
        style={{ width: 600 }}
      />
      {lastRequest ? (
        <pre style={{ margin: 0, fontSize: 12, background: '#f5f5f5', padding: 8, borderRadius: 4, overflow: 'auto' }}>{JSON.stringify(lastRequest, null, 2)}</pre>
      ) : null}
    </Flex>
  );
};

// 全选功能
const SelectAllTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>支持全选:</span>
      <SelectTableList
        allowSelectedAll
        options={productOptions.filter(item => item.status === '在售')}
        columns={productColumns}
        valueKey="id"
        labelKey="productName"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择在售产品"
        style={{ width: 600 }}
      />
    </Flex>
  );
};

const wideEmployeeColumns = [
  { name: 'name', title: '姓名', width: 160 },
  { name: 'department', title: '部门', width: 180 },
  { name: 'position', title: '职位', width: 160 },
  { name: 'email', title: '邮箱', width: 240 },
  { name: 'joinDate', title: '入职日期', width: 140 },
  {
    name: 'status',
    title: '状态',
    width: 120,
    getValueOf: item => <Tag color={item.status === 'active' ? 'success' : 'default'}>{item.status === 'active' ? '在职' : '停用'}</Tag>
  },
  {
    name: 'options',
    title: '操作',
    width: 100,
    getValueOf: item => (
      <Button
        type="link"
        size="small"
        danger
        disabled={item.status === 'inactive'}
        onClick={e => {
          e.stopPropagation();
        }}
      >
        移除
      </Button>
    )
  }
];

// 列宽超出容器:横向滚动条吸附表体底部
const WideTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>横向超宽表格:</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>列只设 width、不要写 span。总宽超出选择面板时出现横向滚动,滚动条在表体可视区域底部,表头保持固定。</div>
      <SelectTableList
        allowSelectedAll
        options={employeeOptions}
        columns={wideEmployeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择员工"
        style={{ width: 600 }}
      />
      {value.length > 0 && (
        <div>
          已选 {value.length} 人:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

// 自定义底部
const CustomFooterExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>自定义底部操作:</span>
      <SelectTableList
        options={employeeOptions}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择员工"
        footer={({ close, reload }) => (
          <Flex justify="space-between" align="center">
            <Button type="link" onClick={reload}>
              刷新数据
            </Button>
            <Button type="primary" onClick={close}>
              确认选择
            </Button>
          </Flex>
        )}
        style={{ width: 600 }}
      />
    </Flex>
  );
};

// 直接展示在页面上(无触发器)
const DirectRenderExample = () => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>直接展示在页面(嵌入模式):</span>
      <SelectTableList
        options={employeeOptions}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        placeholder="请选择员工"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return item.name.toLowerCase().includes(keyword) || item.email.toLowerCase().includes(keyword) || item.department.toLowerCase().includes(keyword);
        }}
        style={{ width: '100%' }}
        renderContent={content => (
          <div
            style={{
              border: '1px solid #d9d9d9',
              borderRadius: 6,
              padding: 16
            }}
          >
            {content}
          </div>
        )}
      />
      {value.length > 0 && (
        <div style={{ padding: '8px 12px', backgroundColor: '#e6f4ff', borderRadius: 4 }}>
          已选择 {value.length} 人:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

const EmployeeMobileCard = ({ item, checked, disabled, onToggle }) => {
  const statusColor = item.status === 'active' ? 'success' : 'default';
  const statusText = item.status === 'active' ? '在职' : '停用';

  return (
    <div
      onClick={() => {
        if (!disabled) {
          onToggle();
        }
      }}
      style={{
        display: 'flex',
        alignItems: 'flex-start',
        gap: 12,
        padding: '12px 16px',
        background: checked ? 'var(--primary-color-1, #e6f4ff)' : '#fff',
        border: &#96;1px solid ${checked ? 'var(--primary-color-2, #91caff)' : '#f0f0f0'}&#96;,
        borderRadius: 12,
        boxSizing: 'border-box',
        cursor: disabled ? 'not-allowed' : 'pointer'
      }}
    >
      <Checkbox checked={checked} disabled={disabled} onClick={e => e.stopPropagation()} onChange={onToggle} style={{ marginTop: 2, flexShrink: 0 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        {/* 主信息:姓名 + 状态 */}
        <Flex justify="space-between" align="center" gap={8} style={{ marginBottom: 6 }}>
          <Flex align="center" gap={8} style={{ flex: 1, minWidth: 0 }}>
            <Avatar size="small" style={{ backgroundColor: '#1677ff', flexShrink: 0 }}>
              {item.name.slice(-2)}
            </Avatar>
            <span
              style={{
                fontSize: 16,
                fontWeight: 600,
                color: 'rgba(0,0,0,0.88)',
                lineHeight: '22px',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
                whiteSpace: 'nowrap'
              }}
            >
              {item.name}
            </span>
          </Flex>
          <Tag color={statusColor} style={{ margin: 0, flexShrink: 0 }}>
            {statusText}
          </Tag>
        </Flex>
        {/* 次要信息:部门 · 职位 */}
        <div style={{ fontSize: 13, color: 'rgba(0,0,0,0.65)', lineHeight: '20px', marginBottom: 4 }}>
          {item.department}
          <span style={{ margin: '0 6px', color: 'rgba(0,0,0,0.25)' }}>·</span>
          {item.position}
        </div>
        {/* 辅助信息:邮箱 / 入职日期 */}
        <div style={{ fontSize: 12, color: 'rgba(0,0,0,0.45)', lineHeight: '18px' }}>
          {item.email}
          <span style={{ margin: '0 6px', color: 'rgba(0,0,0,0.25)' }}>·</span>
          入职 {item.joinDate}
        </div>
      </div>
    </div>
  );
};

// 自定义移动端卡片:突出主 / 次 / 辅层次
const CustomMobileCardExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>自定义移动端卡片(renderMobile):</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>仅移动端生效。主信息为大号姓名,次要为部门/职位,辅助为邮箱与入职日期。桌面端仍为普通表格。</div>
      <SelectTableList
        options={employeeOptions}
        columns={employeeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择员工"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return item.name.toLowerCase().includes(keyword) || item.email.toLowerCase().includes(keyword) || item.department.toLowerCase().includes(keyword);
        }}
        style={{ width: 600 }}
        renderMobile={({ list, value: selected, setValue: setSelected, props: selectProps, isSelectedAll }) => (
          <Flex vertical gap={12} style={{ padding: '0 0 12px' }}>
            {list.map(item => {
              const isChecked = selected.some(target => target.id === item.id);
              return (
                <EmployeeMobileCard
                  key={item.id}
                  item={item}
                  checked={(isSelectedAll && !item.disabled) || isChecked}
                  disabled={isSelectedAll || item.disabled}
                  onToggle={() => {
                    if (item.disabled || isSelectedAll) {
                      return;
                    }
                    if (selectProps.single) {
                      setSelected([item]);
                      return;
                    }
                    setSelected(prev => (isChecked ? prev.filter(target => target.id !== item.id) : [...prev, item]));
                  }}
                />
              );
            })}
          </Flex>
        )}
      />
      {value.length > 0 && (
        <div>
          已选 {value.length} 人:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

const orgTreeColumns = [
  { name: 'name', title: '名称', span: 8 },
  { name: 'code', title: '编码', span: 6 },
  { name: 'owner', title: '负责人', span: 6 },
  {
    name: 'employeeCount',
    title: '人数',
    span: 4,
    getValueOf: item => item.employeeCount ?? '-'
  }
];

const orgTreeData = [
  {
    id: 'east',
    name: '华东区',
    code: 'EAST',
    owner: '张三',
    employeeCount: 120,
    children: [
      {
        id: 'east-sh',
        name: '上海',
        code: 'SH',
        owner: '李四',
        employeeCount: 80,
        children: [
          { id: 'east-sh-pd', name: '浦东分部', code: 'SH-PD', owner: '王五', employeeCount: 40 },
          { id: 'east-sh-xh', name: '徐汇分部', code: 'SH-XH', owner: '赵六', employeeCount: 40 }
        ]
      },
      { id: 'east-hz', name: '杭州', code: 'HZ', owner: '钱七', employeeCount: 40 }
    ]
  },
  {
    id: 'north',
    name: '华北区',
    code: 'NORTH',
    owner: '孙八',
    employeeCount: 60,
    children: [{ id: 'north-bj', name: '北京', code: 'BJ', owner: '周九', employeeCount: 60 }]
  }
];

const orgTreeListData = [
  { id: 'east', name: '华东区', code: 'EAST', owner: '张三', employeeCount: 120, parentId: null },
  { id: 'east-sh', name: '上海', code: 'SH', owner: '李四', employeeCount: 80, parentId: 'east' },
  { id: 'east-sh-pd', name: '浦东分部', code: 'SH-PD', owner: '王五', employeeCount: 40, parentId: 'east-sh' },
  { id: 'east-sh-xh', name: '徐汇分部', code: 'SH-XH', owner: '赵六', employeeCount: 40, parentId: 'east-sh' },
  { id: 'east-hz', name: '杭州', code: 'HZ', owner: '钱七', employeeCount: 40, parentId: 'east' },
  { id: 'north', name: '华北区', code: 'NORTH', owner: '孙八', employeeCount: 60, parentId: '' },
  { id: 'north-bj', name: '北京', code: 'BJ', owner: '周九', employeeCount: 60, parentId: 'north' }
];

const lazyRootData = [
  { id: 'org-1', name: '集团总部', code: 'HQ', owner: '张三', parentId: null, hasChildren: true },
  { id: 'org-2', name: '分公司', code: 'BR', owner: '李四', parentId: null, hasChildren: true }
];

const lazyChildrenMap = {
  'org-1': [
    { id: 'org-1-1', name: '研发中心', code: 'RD', owner: '王五', hasChildren: true },
    { id: 'org-1-2', name: '市场部', code: 'MKT', owner: '赵六', hasChildren: false }
  ],
  'org-1-1': [
    { id: 'org-1-1-1', name: '前端组', code: 'FE', owner: '钱七', hasChildren: false },
    { id: 'org-1-1-2', name: '后端组', code: 'BE', owner: '孙八', hasChildren: false }
  ],
  'org-2': [{ id: 'org-2-1', name: '华南办', code: 'SC', owner: '周九', hasChildren: false }]
};

// dataType=tree:嵌套 children
const TreeTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>树形表格(dataType=tree):</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>嵌套 children 数据;默认展开;多选时父子勾选关联为 parent(勾父级只保留父级值)。</div>
      <SelectTableList
        dataType="tree"
        defaultExpandedKeys
        options={orgTreeData}
        columns={orgTreeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择组织节点"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword) || (item.owner || '').toLowerCase().includes(keyword);
        }}
        style={{ width: 600 }}
      />
      {value.length > 0 && (
        <div>
          已选 {value.length} 项:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

// dataType=treeList:扁平 parentId
const TreeListTableExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>树形表格(dataType=treeList):</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>扁平列表按 parentId 组装为树;支持搜索时保留匹配节点的祖先路径。</div>
      <SelectTableList
        dataType="treeList"
        defaultExpandedKeys
        options={orgTreeListData}
        columns={orgTreeColumns}
        valueKey="id"
        labelKey="name"
        parentKey="parentId"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择组织节点"
        getSearchCallback={({ searchText }, item) => {
          if (!searchText) return true;
          const keyword = searchText.toLowerCase();
          return item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);
        }}
        style={{ width: 600 }}
      />
      {value.length > 0 && (
        <div>
          已选 {value.length} 项:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

// checkRelation:parent / all / independent
const TreeCheckRelationExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);
  const [checkRelation, setCheckRelation] = useState('parent');

  return (
    <Flex vertical gap={8}>
      <span>树形勾选关联(checkRelation):</span>
      <Radio.Group
        value={checkRelation}
        optionType="button"
        options={[
          { label: 'parent', value: 'parent' },
          { label: 'all', value: 'all' },
          { label: 'independent', value: 'independent' }
        ]}
        onChange={e => {
          setCheckRelation(e.target.value);
          setValue([]);
        }}
      />
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>parent:勾父级只留父级值;all:值含父级与全部子孙;independent:父子互不影响。</div>
      <SelectTableList
        dataType="treeList"
        defaultExpandedKeys
        checkRelation={checkRelation}
        options={orgTreeListData}
        columns={orgTreeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择组织节点"
        style={{ width: 600 }}
      />
      {value.length > 0 && <div>已选 key:{value.map(item => item.id).join(', ')}</div>}
    </Flex>
  );
};

// 懒加载:hasChildren + onLoadChildren + mergeTreeChildren
const TreeLazyLoadExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);
  const [lazyData, setLazyData] = useState(lazyRootData);

  const handleLoadChildren = (item, { key }) =>
    new Promise(resolve => {
      setTimeout(() => {
        const children = lazyChildrenMap[key] || [];
        setLazyData(prev =>
          mergeTreeChildren(prev, children, {
            parentKeyValue: key,
            dataType: 'treeList',
            rowKey: 'id',
            parentKey: 'parentId',
            hasChildrenKey: 'hasChildren'
          })
        );
        resolve();
      }, 600);
    });

  return (
    <Flex vertical gap={8}>
      <span>树形懒加载:</span>
      <div style={{ color: '#666', fontSize: 12, lineHeight: 1.6 }}>hasChildren=true 且本地无子节点时展开触发 onLoadChildren,用 mergeTreeChildren 合并子节点。</div>
      <SelectTableList
        dataType="treeList"
        options={lazyData}
        columns={orgTreeColumns}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择组织节点"
        onLoadChildren={handleLoadChildren}
        style={{ width: 600 }}
      />
      {value.length > 0 && (
        <div>
          已选 {value.length} 项:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

const BaseExample = () => {
  const [isPopup, setIsPopup] = useState(true);

  return (
    <Flex vertical gap={24}>
      <Flex align="center" gap={12}>
        <span>展示模式:</span>
        <Switch checked={isPopup} onChange={setIsPopup} checkedChildren="下拉" unCheckedChildren="弹窗" />
        <span style={{ color: '#666', fontSize: 12 }}>{isPopup ? '点击输入框展开下拉菜单' : '点击输入框打开弹窗'}</span>
      </Flex>
      <Divider />
      <BasicTableExample isPopup={isPopup} />
      <Divider />
      <SingleTableExample isPopup={isPopup} />
      <Divider />
      <SearchableTableExample isPopup={isPopup} />
      <Divider />
      <RemoteSearchTableExample isPopup={isPopup} />
      <Divider />
      <RemoteSearchLoadMoreExample isPopup={isPopup} />
      <Divider />
      <SelectAllTableExample isPopup={isPopup} />
      <Divider />
      <WideTableExample isPopup={isPopup} />
      <Divider />
      <CustomFooterExample isPopup={isPopup} />
      <Divider />
      <CustomMobileCardExample isPopup={isPopup} />
      <Divider />
      <TreeTableExample isPopup={isPopup} />
      <Divider />
      <TreeListTableExample isPopup={isPopup} />
      <Divider />
      <TreeCheckRelationExample isPopup={isPopup} />
      <Divider />
      <TreeLazyLoadExample isPopup={isPopup} />
      <Divider />
      <DirectRenderExample />
    </Flex>
  );
};

render(<BaseExample />);
  • SelectTree 树形选择
  • 树形结构的选择组件,适用于组织架构、地区、分类等层级数据的选择
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { SelectTree } = _SuperSelect;
const { Space, Button, Flex, Divider, Tag, Switch } = antd;
const { useState } = React;

// 组织架构数据
const organizationTree = [
  {
    id: 'root',
    parentId: null,
    name: '集团总部',
    code: 'HQ',
    employeeCount: 500
  },
  {
    id: 'tech',
    parentId: 'root',
    name: '技术中心',
    code: 'TECH',
    employeeCount: 200
  },
  {
    id: 'tech-fe',
    parentId: 'tech',
    name: '前端开发组',
    code: 'FE',
    employeeCount: 50
  },
  {
    id: 'tech-be',
    parentId: 'tech',
    name: '后端开发组',
    code: 'BE',
    employeeCount: 80
  },
  {
    id: 'tech-qa',
    parentId: 'tech',
    name: '质量保障组',
    code: 'QA',
    employeeCount: 30
  },
  {
    id: 'tech-devops',
    parentId: 'tech',
    name: '运维组',
    code: 'DEVOPS',
    employeeCount: 20
  },
  {
    id: 'product',
    parentId: 'root',
    name: '产品中心',
    code: 'PRODUCT',
    employeeCount: 100
  },
  {
    id: 'product-design',
    parentId: 'product',
    name: '产品设计组',
    code: 'DESIGN',
    employeeCount: 40
  },
  {
    id: 'product-pm',
    parentId: 'product',
    name: '项目管理组',
    code: 'PM',
    employeeCount: 30
  },
  {
    id: 'operation',
    parentId: 'root',
    name: '运营中心',
    code: 'OP',
    employeeCount: 80
  },
  {
    id: 'operation-marketing',
    parentId: 'operation',
    name: '市场营销组',
    code: 'MARKETING',
    employeeCount: 50
  },
  {
    id: 'operation-cs',
    parentId: 'operation',
    name: '客户服务组',
    code: 'CS',
    employeeCount: 30
  },
  {
    id: 'hr',
    parentId: 'root',
    name: '人力资源部',
    code: 'HR',
    employeeCount: 40
  },
  {
    id: 'finance',
    parentId: 'root',
    name: '财务部',
    code: 'FINANCE',
    employeeCount: 30
  }
];

// 地区数据
const regionTree = [
  {
    id: 'china',
    parentId: null,
    name: '中国',
    code: 'CN'
  },
  {
    id: 'beijing',
    parentId: 'china',
    name: '北京市',
    code: 'BJ'
  },
  {
    id: 'shanghai',
    parentId: 'china',
    name: '上海市',
    code: 'SH'
  },
  {
    id: 'guangdong',
    parentId: 'china',
    name: '广东省',
    code: 'GD'
  },
  {
    id: 'guangzhou',
    parentId: 'guangdong',
    name: '广州市',
    code: 'GZ'
  },
  {
    id: 'shenzhen',
    parentId: 'guangdong',
    name: '深圳市',
    code: 'SZ'
  },
  {
    id: 'zhejiang',
    parentId: 'china',
    name: '浙江省',
    code: 'ZJ'
  },
  {
    id: 'hangzhou',
    parentId: 'zhejiang',
    name: '杭州市',
    code: 'HZ'
  },
  {
    id: 'jiangsu',
    parentId: 'china',
    name: '江苏省',
    code: 'JS'
  },
  {
    id: 'nanjing',
    parentId: 'jiangsu',
    name: '南京市',
    code: 'NJ'
  },
  {
    id: 'usa',
    parentId: null,
    name: '美国',
    code: 'US'
  },
  {
    id: 'newyork',
    parentId: 'usa',
    name: '纽约州',
    code: 'NY'
  },
  {
    id: 'california',
    parentId: 'usa',
    name: '加利福尼亚州',
    code: 'CA'
  }
];

// 分类数据
const categoryTree = [
  {
    id: 'electronics',
    parentId: null,
    name: '电子产品'
  },
  {
    id: 'phone',
    parentId: 'electronics',
    name: '手机'
  },
  {
    id: 'computer',
    parentId: 'electronics',
    name: '电脑'
  },
  {
    id: 'laptop',
    parentId: 'computer',
    name: '笔记本'
  },
  {
    id: 'desktop',
    parentId: 'computer',
    name: '台式机'
  },
  {
    id: 'clothing',
    parentId: null,
    name: '服装'
  },
  {
    id: 'mens',
    parentId: 'clothing',
    name: '男装'
  },
  {
    id: 'womens',
    parentId: 'clothing',
    name: '女装'
  }
];

// 基础树选择
const BasicTreeExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>组织架构多选:</span>
      <SelectTree
        options={organizationTree}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择部门"
        style={{ width: 320 }}
      />
      {value.length > 0 && (
        <Flex wrap gap={4}>
          {value.map(item => (
            <Tag key={item.id} color="blue">{item.name}</Tag>
          ))}
        </Flex>
      )}
    </Flex>
  );
};

// 单选树
const SingleTreeExample = ({ isPopup }) => {
  const [value, setValue] = useState(null);

  return (
    <Flex vertical gap={8}>
      <span>地区单选:</span>
      <SelectTree
        single
        options={regionTree}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择地区"
        style={{ width: 320 }}
      />
      {value && <Tag color="green">已选:{value.name} ({value.code})</Tag>}
    </Flex>
  );
};

// 带搜索的树选择
const SearchableTreeExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>带搜索功能:</span>
      <SelectTree
        options={organizationTree}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="搜索部门名称或编码"
        style={{ width: 320 }}
      />
    </Flex>
  );
};

// 分类选择
const CategoryTreeExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>商品分类选择:</span>
      <SelectTree
        options={categoryTree}
        valueKey="id"
        labelKey="name"
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        placeholder="请选择分类"
        style={{ width: 320 }}
      />
      {value.length > 0 && (
        <div>已选分类:{value.map(item => item.name).join(' > ')}</div>
      )}
    </Flex>
  );
};

const BaseExample = () => {
  const [isPopup, setIsPopup] = useState(true);

  return (
    <Flex vertical gap={24}>
      <Flex align="center" gap={12}>
        <span>展示模式:</span>
        <Switch
          checked={isPopup}
          onChange={setIsPopup}
          checkedChildren="下拉"
          unCheckedChildren="弹窗"
        />
        <span style={{ color: '#666', fontSize: 12 }}>
          {isPopup ? '点击输入框展开下拉菜单' : '点击输入框打开弹窗'}
        </span>
      </Flex>
      <Divider />
      <BasicTreeExample isPopup={isPopup} />
      <Divider />
      <SingleTreeExample isPopup={isPopup} />
      <Divider />
      <SearchableTreeExample isPopup={isPopup} />
      <Divider />
      <CategoryTreeExample isPopup={isPopup} />
    </Flex>
  );
};

render(<BaseExample />);
  • Ref 使用方法
  • 展示如何通过 ref 控制选择器的打开/关闭、获取/设置值、程序化选择等操作
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { default: SuperSelect } = _SuperSelect;
const { Space, Button, Flex, Divider, message } = antd;
const { useRef, useState } = React;

// 基础 ref 操作示例
const BasicRefExample = () => {
  const selectRef = useRef();
  const [value, setValue] = useState([]);

  const departmentOptions = [
    { value: 'tech', label: '技术研发部' },
    { value: 'product', label: '产品设计部' },
    { value: 'operation', label: '运营管理部' },
    { value: 'hr', label: '人力资源部' }
  ];

  return (
    <Flex vertical gap={12}>
      <span>通过 ref 控制选择器:</span>
      <Flex gap={8}>
        <SuperSelect
          ref={selectRef}
          options={departmentOptions}
          value={value}
          onChange={setValue}
          placeholder="请选择部门"
          style={{ width: 240 }}
        />
        <Button type="primary" onClick={() => selectRef.current?.onOpenChange(true)}>
          打开
        </Button>
        <Button onClick={() => selectRef.current?.onOpenChange(false)}>
          关闭
        </Button>
      </Flex>
    </Flex>
  );
};

// 完整 ref 属性展示
const FullRefExample = () => {
  const selectRef = useRef();
  const [value, setValue] = useState([]);
  const [log, setLog] = useState([]);

  const addLog = (msg) => {
    setLog(prev => [...prev, &#96;[${new Date().toLocaleTimeString()}] ${msg}&#96;]);
  };

  const userOptions = Array.from({ length: 15 }).map((_, i) => ({
    value: &#96;user_${i + 1}&#96;,
    label: &#96;用户${i + 1}&#96;
  }));

  const handleGetValue = () => {
    const currentValue = selectRef.current?.value || [];
    addLog(&#96;当前值: ${JSON.stringify(currentValue.map(v => v.label))}&#96;);
    message.info(&#96;已选 ${currentValue.length} 项&#96;);
  };

  const handleClear = () => {
    selectRef.current?.setValue([]);
    addLog('已清空选择');
  };

  const handleSelectFirst = () => {
    const firstOption = userOptions[0];
    if (firstOption) {
      selectRef.current?.onSelect(firstOption);
      addLog(&#96;已选择: ${firstOption.label}&#96;);
    }
  };

  return (
    <Flex vertical gap={12}>
      <span>ref 完整功能展示:</span>
      <Flex gap={8} wrap>
        <SuperSelect
          ref={selectRef}
          options={userOptions}
          value={value}
          onChange={setValue}
          placeholder="请选择用户"
          style={{ width: 240 }}
        />
      </Flex>
      <Flex gap={8} wrap>
        <Button type="primary" onClick={() => selectRef.current?.onOpenChange(true)}>
          打开下拉
        </Button>
        <Button onClick={() => selectRef.current?.onOpenChange(false)}>
          关闭下拉
        </Button>
        <Button onClick={handleGetValue}>
          获取当前值
        </Button>
        <Button onClick={handleClear}>
          清空选择
        </Button>
        <Button onClick={handleSelectFirst}>
          选择第一项
        </Button>
      </Flex>
      <div style={{
        background: '#f5f5f5',
        padding: 12,
        borderRadius: 4,
        maxHeight: 120,
        overflow: 'auto',
        fontSize: 12
      }}>
        <div style={{ marginBottom: 4, fontWeight: 'bold' }}>操作日志:</div>
        {log.length === 0 ? (
          <div style={{ color: '#999' }}>暂无操作</div>
        ) : (
          log.map((item, index) => <div key={index}>{item}</div>)
        )}
      </div>
    </Flex>
  );
};

// ref 常见场景
const CommonScenariosExample = () => {
  const selectRef = useRef();

  const options = [
    { value: 1, label: '选项一' },
    { value: 2, label: '选项二' },
    { value: 3, label: '选项三' }
  ];

  return (
    <Flex vertical gap={12}>
      <span>常见使用场景:</span>
      <Flex gap={8} align="center">
        <SuperSelect
          ref={selectRef}
          options={options}
          placeholder="请选择"
          style={{ width: 200 }}
        />
        <Button
          type="primary"
          onClick={() => {
            selectRef.current?.onOpenChange(true);
          }}
        >
          外部触发打开
        </Button>
      </Flex>
      <div style={{ color: '#666', fontSize: 12 }}>
        提示:ref 可用于表单联动、外部控制弹窗、程序化操作等场景
      </div>
    </Flex>
  );
};

const BaseExample = () => {
  return (
    <Flex vertical gap={24}>
      <BasicRefExample />
      <Divider />
      <FullRefExample />
      <Divider />
      <CommonScenariosExample />
    </Flex>
  );
};

render(<BaseExample />);
  • SelectCascader 级联选择
  • 级联选择组件,支持多列菜单展示、父子关联选择、末级选择限制、搜索过滤等功能
  • _SuperSelect(@kne/current-lib_super-select)[import * as _SuperSelect from "@kne/super-select"],antd(antd),(@kne/current-lib_super-select/dist/index.css)
const { SelectCascader } = _SuperSelect;
const { Space, Button, Flex, Divider, Tag, Switch, message } = antd;
const { useState, useRef } = React;

// 中国地区数据
const regionData = [
  {
    id: 'beijing',
    name: '北京市',
    children: [
      { id: 'haidian', name: '海淀区' },
      { id: 'chaoyang', name: '朝阳区' },
      { id: 'dongcheng', name: '东城区' },
      { id: 'xicheng', name: '西城区' }
    ]
  },
  {
    id: 'shanghai',
    name: '上海市',
    children: [
      { id: 'pudong', name: '浦东新区' },
      { id: 'huangpu', name: '黄浦区' },
      { id: 'jingan', name: '静安区' },
      { id: 'xuhui', name: '徐汇区' }
    ]
  },
  {
    id: 'guangdong',
    name: '广东省',
    children: [
      {
        id: 'guangzhou',
        name: '广州市',
        children: [
          { id: 'tianhe', name: '天河区' },
          { id: 'yuexiu', name: '越秀区' },
          { id: 'panyu', name: '番禺区' }
        ]
      },
      {
        id: 'shenzhen',
        name: '深圳市',
        children: [
          { id: 'nanshan', name: '南山区' },
          { id: 'futian', name: '福田区' },
          { id: 'luohu', name: '罗湖区' }
        ]
      },
      { id: 'dongguan', name: '东莞市' }
    ]
  },
  {
    id: 'zhejiang',
    name: '浙江省',
    children: [
      {
        id: 'hangzhou',
        name: '杭州市',
        children: [
          { id: 'xihu', name: '西湖区' },
          { id: 'binjiang', name: '滨江区' }
        ]
      },
      {
        id: 'ningbo',
        name: '宁波市',
        children: [
          { id: 'haishu', name: '海曙区' },
          { id: 'yinzhou', name: '鄞州区' }
        ]
      }
    ]
  },
  {
    id: 'jiangsu',
    name: '江苏省',
    children: [
      {
        id: 'nanjing',
        name: '南京市',
        children: [
          { id: 'xuanwu', name: '玄武区' },
          { id: 'qinhuai', name: '秦淮区' }
        ]
      },
      {
        id: 'suzhou',
        name: '苏州市',
        children: [
          { id: 'gusu', name: '姑苏区' },
          { id: 'industrial', name: '工业园区' }
        ]
      }
    ]
  }
];

// 组织架构数据
const organizationData = [
  {
    id: 'tech',
    name: '技术研发中心',
    code: 'TECH',
    children: [
      {
        id: 'tech-fe',
        name: '前端开发组',
        code: 'FE',
        children: [
          { id: 'fe-react', name: 'React 团队', code: 'REACT' },
          { id: 'fe-vue', name: 'Vue 团队', code: 'VUE' }
        ]
      },
      {
        id: 'tech-be',
        name: '后端开发组',
        code: 'BE',
        children: [
          { id: 'be-java', name: 'Java 团队', code: 'JAVA' },
          { id: 'be-go', name: 'Go 团队', code: 'GO' }
        ]
      },
      { id: 'tech-qa', name: '质量保障组', code: 'QA' }
    ]
  },
  {
    id: 'product',
    name: '产品设计中心',
    code: 'PRODUCT',
    children: [
      { id: 'product-design', name: 'UI设计组', code: 'DESIGN' },
      { id: 'product-pm', name: '产品经理组', code: 'PM' }
    ]
  },
  {
    id: 'operation',
    name: '运营中心',
    code: 'OP',
    children: [
      { id: 'op-marketing', name: '市场营销组', code: 'MARKETING' },
      { id: 'op-cs', name: '客户服务组', code: 'CS' }
    ]
  }
];

// 商品分类数据
const categoryData = [
  {
    id: 'electronics',
    name: '电子产品',
    children: [
      {
        id: 'phone',
        name: '手机',
        children: [
          { id: 'iphone', name: 'iPhone' },
          { id: 'android', name: '安卓手机' }
        ]
      },
      {
        id: 'computer',
        name: '电脑',
        children: [
          { id: 'laptop', name: '笔记本' },
          { id: 'desktop', name: '台式机' }
        ]
      }
    ]
  },
  {
    id: 'clothing',
    name: '服装',
    children: [
      {
        id: 'mens',
        name: '男装',
        children: [
          { id: 'mens-shirt', name: '衬衫' },
          { id: 'mens-pants', name: '裤子' }
        ]
      },
      {
        id: 'womens',
        name: '女装',
        children: [
          { id: 'womens-dress', name: '连衣裙' },
          { id: 'womens-blouse', name: '上衣' }
        ]
      }
    ]
  }
];

// 超长文字测试数据
const longTextData = [
  {
    id: 'dept-1',
    name: '人工智能与机器学习应用技术研发中心',
    children: [
      {
        id: 'dept-1-1',
        name: '自然语言处理与智能对话系统研发组',
        children: [
          { id: 'dept-1-1-1', name: '大语言模型训练与优化专项小组' },
          { id: 'dept-1-1-2', name: '智能客服机器人产品研发团队' },
          { id: 'dept-1-1-3', name: '多语言机器翻译引擎研发组' },
          { id: 'dept-1-1-4', name: '知识图谱构建与智能问答系统研发小组' },
          { id: 'dept-1-1-5', name: '文本挖掘与情感分析技术研发团队' }
        ]
      },
      {
        id: 'dept-1-2',
        name: '计算机视觉与图像识别技术研发组',
        children: [
          { id: 'dept-1-2-1', name: '工业质检视觉检测算法研发小组' },
          { id: 'dept-1-2-2', name: '人脸识别与活体检测技术研发团队' },
          { id: 'dept-1-2-3', name: '医疗影像AI辅助诊断研发组' },
          { id: 'dept-1-2-4', name: '自动驾驶视觉感知算法研发小组' },
          { id: 'dept-1-2-5', name: '视频内容理解与智能分析研发团队' }
        ]
      },
      {
        id: 'dept-1-3',
        name: '语音识别与合成技术研发小组',
        children: [
          { id: 'dept-1-3-1', name: '端到端语音识别引擎研发团队' },
          { id: 'dept-1-3-2', name: '多风格语音合成与情感表达研发组' }
        ]
      },
      {
        id: 'dept-1-4',
        name: '强化学习与决策智能研发组',
        children: [
          { id: 'dept-1-4-1', name: '智能博弈与游戏AI研发团队' },
          { id: 'dept-1-4-2', name: '机器人控制与路径规划算法研发组' }
        ]
      }
    ]
  },
  {
    id: 'dept-2',
    name: '云计算与大数据平台技术中心',
    children: [
      {
        id: 'dept-2-1',
        name: '分布式存储与计算架构研发组',
        children: [
          { id: 'dept-2-1-1', name: '高可用分布式数据库内核研发团队' },
          { id: 'dept-2-1-2', name: '云原生容器编排与调度系统研发组' },
          { id: 'dept-2-1-3', name: '对象存储与分布式文件系统研发小组' },
          { id: 'dept-2-1-4', name: '微服务架构与服务网格技术研发团队' }
        ]
      },
      {
        id: 'dept-2-2',
        name: '数据中台与数据治理解决方案团队',
        children: [
          { id: 'dept-2-2-1', name: '企业级数据仓库建模与ETL开发组' },
          { id: 'dept-2-2-2', name: '实时数据流处理与计算引擎研发组' },
          { id: 'dept-2-2-3', name: '数据资产管理与元数据管理研发小组' },
          { id: 'dept-2-2-4', name: '数据质量监控与异常检测系统研发团队' }
        ]
      },
      {
        id: 'dept-2-3',
        name: '云安全与合规性保障研发组',
        children: [
          { id: 'dept-2-3-1', name: '云原生安全架构与容器安全研发团队' },
          { id: 'dept-2-3-2', name: '数据加密与密钥管理系统研发组' }
        ]
      }
    ]
  },
  {
    id: 'dept-3',
    name: '网络安全与隐私保护技术中心',
    children: [
      {
        id: 'dept-3-1',
        name: '网络攻防与安全应急响应团队',
        children: [
          { id: 'dept-3-1-1', name: '威胁情报分析与安全态势感知研发组' },
          { id: 'dept-3-1-2', name: '零信任安全架构与企业安全网关研发组' },
          { id: 'dept-3-1-3', name: '漏洞挖掘与渗透测试技术研发小组' },
          { id: 'dept-3-1-4', name: '安全编排自动化与响应(SOAR)平台研发团队' }
        ]
      },
      {
        id: 'dept-3-2',
        name: '数据隐私计算与联邦学习研发小组',
        children: [
          { id: 'dept-3-2-1', name: '多方安全计算与隐私求交技术研发团队' },
          { id: 'dept-3-2-2', name: '联邦学习平台与隐私保护机器学习研发组' }
        ]
      }
    ]
  },
  {
    id: 'dept-4',
    name: '智能硬件与物联网技术研发中心',
    children: [
      {
        id: 'dept-4-1',
        name: '嵌入式系统与边缘计算研发组',
        children: [
          { id: 'dept-4-1-1', name: '物联网设备固件与操作系统研发团队' },
          { id: 'dept-4-1-2', name: '边缘AI推理与模型优化部署研发小组' },
          { id: 'dept-4-1-3', name: '工业物联网网关与协议转换研发组' }
        ]
      },
      {
        id: 'dept-4-2',
        name: '智能传感器与MEMS技术研发团队',
        children: [
          { id: 'dept-4-2-1', name: '多模态传感器融合算法研发小组' },
          { id: 'dept-4-2-2', name: '环境感知与智能检测传感器研发组' }
        ]
      },
      {
        id: 'dept-4-3',
        name: '智能家居与消费电子解决方案团队',
        children: [
          { id: 'dept-4-3-1', name: '智能音箱与语音交互产品研发小组' },
          { id: 'dept-4-3-2', name: '智能穿戴设备与健康监测研发团队' },
          { id: 'dept-4-3-3', name: '智能家居控制中枢与生态系统研发组' }
        ]
      }
    ]
  },
  {
    id: 'dept-5',
    name: '企业数字化转型与咨询服务事业部',
    children: [
      {
        id: 'dept-5-1',
        name: '行业解决方案与数字化咨询团队',
        children: [
          { id: 'dept-5-1-1', name: '金融行业数字化解决方案与实施团队' },
          { id: 'dept-5-1-2', name: '制造业智能制造与工业互联网咨询组' },
          { id: 'dept-5-1-3', name: '医疗健康行业数字化转型解决方案团队' },
          { id: 'dept-5-1-4', name: '零售电商与新零售数字化咨询研发组' }
        ]
      },
      {
        id: 'dept-5-2',
        name: '项目交付与技术支持服务团队',
        children: [
          { id: 'dept-5-2-1', name: '企业级系统架构设计与集成实施小组' },
          { id: 'dept-5-2-2', name: '客户成功与售后技术支持服务团队' }
        ]
      }
    ]
  }
];

// 基础级联选择
const BasicExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);
  return (
    <Flex vertical gap={8}>
      <span>地区多选(父子关联):</span>
      <SelectCascader
        options={regionData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        placeholder="请选择地区"
        menuItemWidth={160}
        style={{ width: 320 }}
      />
      {value.length > 0 && (
        <Flex wrap gap={4}>
          {value.map(item => (
            <Tag key={item.id} color="blue">{item.name}</Tag>
          ))}
        </Flex>
      )}
    </Flex>
  );
};

// 单选模式
const SingleExample = ({ isPopup }) => {
  const [value, setValue] = useState(null);
  return (
    <Flex vertical gap={8}>
      <span>地区单选:</span>
      <SelectCascader
        single
        options={regionData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        placeholder="请选择地区"
        menuItemWidth={160}
        style={{ width: 320 }}
      />
      {value && <Tag color="green">已选:{value.name}</Tag>}
    </Flex>
  );
};

// 只选末级
const OnlyLastLevelExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>只允许选择末级节点:</span>
      <SelectCascader
        options={organizationData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        onlyAllowLastLevel
        placeholder="请选择团队"
        menuItemWidth={180}
        style={{ width: 360 }}
      />
      {value.length > 0 && (
        <div>
          已选团队:{value.map(item => item.name).join('、')}
        </div>
      )}
    </Flex>
  );
};

// 数量限制
const MaxLimitExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>最多选择 3 项:</span>
      <SelectCascader
        options={regionData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        maxLength={3}
        placeholder="请选择地区(最多3项)"
        menuItemWidth={160}
        style={{ width: 320 }}
      />
      <Tag color={value.length >= 3 ? 'red' : 'blue'}>
        已选择 {value.length}/3 项
      </Tag>
    </Flex>
  );
};

// 带搜索功能
const SearchExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>带搜索功能:</span>
      <SelectCascader
        options={regionData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        onSearch={(searchText, { mapping }) => {
          return Array.from(mapping.values()).filter(item => 
            item.name.toLowerCase().includes(searchText.toLowerCase())
          );
        }}
        searchPlaceholder="搜索地区名称"
        placeholder="搜索并选择地区"
        menuItemWidth={160}
        style={{ width: 360 }}
      />
    </Flex>
  );
};

// 商品分类选择
const CategoryExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>商品分类选择:</span>
      <SelectCascader
        options={categoryData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        placeholder="请选择商品分类"
        menuItemWidth={160}
        style={{ width: 320 }}
      />
      {value.length > 0 && (
        <div>
          已选分类:{value.map(item => item.name).join(' > ')}
        </div>
      )}
    </Flex>
  );
};

// 超长文字测试
const LongTextExample = ({ isPopup }) => {
  const [value, setValue] = useState([]);

  return (
    <Flex vertical gap={8}>
      <span>超长文字省略测试(部门选择):</span>
      <SelectCascader
        options={longTextData}
        value={value}
        onChange={setValue}
        isPopup={isPopup}
        valueKey="id"
        labelKey="name"
        placeholder="请选择部门"
        menuItemWidth={200}
        style={{ width: 400 }}
      />
      {value.length > 0 && (
        <Flex wrap gap={4}>
          {value.map(item => (
            <Tag key={item.id} color="purple" style={{ maxWidth: 200, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {item.name}
            </Tag>
          ))}
        </Flex>
      )}
    </Flex>
  );
};

const BaseExample = () => {
  const [isPopup, setIsPopup] = useState(true);

  return (
    <Flex vertical gap={24}>
      <Flex align="center" gap={12}>
        <span>展示模式:</span>
        <Switch
          checked={isPopup}
          onChange={setIsPopup}
          checkedChildren="下拉"
          unCheckedChildren="弹窗"
        />
        <span style={{ color: '#666', fontSize: 12 }}>
          {isPopup ? '点击输入框展开下拉菜单' : '点击输入框打开弹窗'}
        </span>
      </Flex>
      <Divider />
      <BasicExample isPopup={isPopup} />
      <Divider />
      <SingleExample isPopup={isPopup} />
      <Divider />
      <OnlyLastLevelExample isPopup={isPopup} />
      <Divider />
      <MaxLimitExample isPopup={isPopup} />
      <Divider />
      <SearchExample isPopup={isPopup} />
      <Divider />
      <CategoryExample isPopup={isPopup} />
      <Divider />
      <LongTextExample isPopup={isPopup} />
    </Flex>
  );
};

render(<BaseExample />);

API

SelectInput

基础选择输入组件,提供核心的选择功能和状态管理。

| 属性名 | 说明 | 类型 | 默认值 | | ---------------- | --------------------------------- | ------------------------------- | ------------------------------- | | value | 当前选中的值 | array | object | [] | | defaultValue | 默认选中的值 | array | object | [] | | onChange | 选中值变化时的回调函数 | function(value) | - | | single | 是否单选模式 | boolean | false