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

@stoly/react-component

v1.0.6

Published

antd6.x 组件封装

Readme

@stoly/react-component

基于 antd 6.x 封装的 React 业务组件库,提供表格查询、弹窗、布局、Excel 导出等开箱即用的能力。

安装

npm install @stoly/react-component
# 或
pnpm add @stoly/react-component

安装 Agent Skill

本库附带 Agent Skill,安装后 AI 编码助手(Cursor / Claude Code 等)能自动获得组件用法指引。

# 安装到当前项目
npx skills add ./node_modules/@stoly/react-component

# 全局安装(跨项目可用)
npx skills add ./node_modules/@stoly/react-component -g

Peer Dependencies

请确保项目中已安装以下依赖:

{
  "@ant-design/icons": ">=6",
  "antd": ">=6",
  "react": ">=19",
  "react-dom": ">=19",
  "styled-components": "6.x",
  "lodash-es": ">=4.17.21",
  "rc-scrollbars": "^1.1.6",
  "react-router-dom": "6.x",
  "copy-to-clipboard": "^3.3.3",
  "exceljs": "^4.4.0",
  "react-draggable": "^4.4.6",
  "scroll-into-view-if-needed": "^3.1.0"
}

快速开始

一个典型的「表格查询 + 弹窗」页面:

import { useRef } from 'react'
import { Form, Input, Space } from 'antd'
import { RcTable, RcTableForm, RcModal, type RcTableRef, type RcQueryData } from '@stoly/react-component'

interface Query extends RcQueryData {
  name?: string
}

interface Row {
  id: number
  name: string
}

const ListPage = () => {
  const query = RcTableForm.useQuery<Query>()
  const controller = RcTableForm.useController()
  const modal = RcModal.useModal<Row>()
  const tableRef = useRef<RcTableRef<Row>>(null)

  const columns = [
    { title: '姓名', dataIndex: 'name', key: 'name' },
    {
      ...RcTable.OperateColumnProps,
      render: (_: unknown, record: Row) => (
        <Space>
          <a onClick={() => modal.open(record)}>编辑</a>
          <a onClick={() => RcModal.confirm({ api: deleteApi, params: record.id, query })}>
            删除
          </a>
        </Space>
      ),
    },
  ]

  return (
    <>
      <RcTableForm<Query> query={query} controller={controller}>
        <Form.Item name="name" label="姓名">
          <Input placeholder="请输入姓名" />
        </Form.Item>
      </RcTableForm>

      <RcTable<Row, any, any, Query>
        ref={tableRef}
        query={query}
        api={fetchList}
        queryFormat={(q) => q}
        dataFormat={(res) => ({ rows: res.data.list, total: res.data.total })}
        columns={columns}
        rowKey="id"
      />

      <RcModal title="编辑" open={modal.visable} onCancel={modal.close} fullScreenModal>
        {/* 弹窗内容 */}
      </RcModal>
    </>
  )
}

组件

RcTable 数据表格

对 antd Table 的增强封装,集成数据请求、分页、排序、右键菜单、列配置、密度切换等功能。

Props

继承 antd TableProps<T>(移除 dataSource / loading / components / onChange

| 属性 | 类型 | 必传 | 说明 | |------|------|:----:|------| | query | SearchQuery<Q> | ✅ | 查询条件,由 RcTableForm.useQuery 创建 | | api | (params: P) => Promise<R> | ✅ | 数据请求接口 | | queryFormat | (q: Q) => P | ✅ | 查询条件 → 接口参数的转换函数 | | dataFormat | (res: R) => { rows: T[], total: number } | ✅ | 接口返回值 → 表格数据的转换函数 | | showIndex | boolean | - | 显示序号列(按当前页计算) | | exported | boolean | - | 启用右键导出 Excel(仅适用于简单表头) |

Ref

通过 ref 获取表格实例:

const tableRef = useRef<RcTableRef<Row>>(null)
const data = tableRef.current?.getCurrentData() // { rows, total }

静态属性

  • RcTable.OperateColumnProps — 操作列默认配置:

    { align: 'center', title: '操作', width: 120, fixed: 'right', className: 'noCopy' }
  • RcTable.Context — 通过 render props 获取当前表格数据

内置功能

  • 右键菜单:刷新、复制单元格、复制行、导出行/导出当前页(需开启 exported
  • 列配置:通过底部齿轮按钮切换列可见性,拖拽排序
  • 密度切换:默认 / 紧凑
  • 回到顶部:滚动超过 100px 时显示

RcTableForm 查询表单

RcTable 配合使用的查询表单,自动管理查询/重置/分页逻辑。

Props

继承 antd FormProps<T>(移除 form

| 属性 | 类型 | 必传 | 说明 | |------|------|:----:|------| | query | SearchQuery<T> | ✅ | 查询条件 | | controller | TableFormController | ✅ | 表单控制器 | | customButtons | ReactNode | - | 替换默认的查询/重置按钮 | | extra | ReactNode | - | 按钮区域的额外内容 | | defaultShowMore | boolean | - | 默认展开更多筛选条件 |

静态方法

// 创建查询条件,默认 { pageNum: 1, pageSize: 20 }
const query = RcTableForm.useQuery<Query>(initValues?)

// 创建表单控制器
const controller = RcTableForm.useController()

// 控制器方法
controller.submit()           // 触发查询
controller.clear(fields?)     // 重置表单(可指定字段)

自动展开/收起

当表单内容高度超过一行时,自动出现「展开/收起筛选」按钮。


RcModal 可拖拽弹窗

对 antd Modal 的增强,支持拖拽标题栏移动和全屏切换。

Props

继承 antd ModalProps(移除 modalRender

| 属性 | 类型 | 必传 | 说明 | |------|------|:----:|------| | fullScreenModal | boolean | - | 显示全屏/退出全屏按钮 | | autoFullScreen | boolean | - | 默认以全屏打开 | | onFullScreenChange | (fullScreen: boolean) => void | - | 全屏状态变化回调 |

RcModal.useModal

管理弹窗的打开/关闭状态及参数传递:

const modal = RcModal.useModal<{ id: number }>()

modal.open({ id: 1 })    // 打开并传参
modal.close()             // 关闭
modal.visable             // 是否可见
modal.params              // 当前参数 { id: 1 }

RcModal.confirm

确认操作弹窗,内置成功提示和表格刷新逻辑:

// 推荐:对象参数形式
RcModal.confirm({
  api: deleteUser,
  params: { id: record.id },
  query,                        // 可选,成功后刷新查询
  tableData,                    // 可选,用于删除最后一条数据后自动翻页
  callback: (res) => {},        // 可选,自定义成功回调
}, {
  title: '删除',                // 可选,默认 '删除'
  content: '确认删除该用户?',   // 可选,默认 '确认是否删除该数据?'
})

弹窗页面 Props

弹窗内的表单页面建议实现此接口:

interface RcModalProps<P = unknown> {
  modal: ModalProps<P>          // { visable, params, open, close }
  query?: SearchQuery<QueryData>
}

布局组件

RcLayoutHeader

页面头部布局,左右 flex 排列。

<RcLayoutHeader actions={<Button>设置</Button>}>
  <h1>页面标题</h1>
</RcLayoutHeader>

| 属性 | 类型 | 说明 | |------|------|------| | children | ReactNode | 左侧内容 | | actions | ReactNode | 右侧操作区 |

RcLayoutSider

侧栏布局,内置 Menu 和 Scrollbars。

| 属性 | 类型 | 说明 | |------|------|------| | menuProps | MenuProps(排除 theme/mode) | 菜单配置 | | header | (collapsed) => ReactNode | 侧栏顶部 | | footer | (collapsed) => ReactNode | 侧栏底部 | | trigger | (collapsed) => ReactNode | 折叠按钮 | | scrollBarProps | ScrollbarsProps | 滚动条配置 |

RcLayoutTabPage

标签页布局,支持两种模式:

  • hasSider={true} — 侧栏 + 内容区
  • hasSider={false} — 头部 + 内容区

| 属性 | 类型 | 说明 | |------|------|------| | siderProps | RcLayoutSiderProps | 侧栏配置 | | headerProps | RcLayoutHeaderProps | 头部配置 | | tabPageProps | TabsProps(扩展 tabBarHorizontalMargin) | 标签页配置 | | onTabChange | (key) => void | 标签切换 | | onClose | (key) => void | 关闭标签 | | onCloseOther | (key) => void | 关闭其他标签 | | onRefresh | (key) => void | 刷新标签 |

子组件:

  • RcLayoutTabPage.TabLabel — 可关闭的 tab 标签
  • RcLayoutTabPage.TabContextMenu — tab 右键菜单(关闭/关闭其他/刷新)
  • RcLayoutTabPage.PageContainer — 页面容器(小尺寸 Card + 可选滚动区域)

工具

RcExcel

Excel 导出工具,基于 exceljs(动态导入,不影响首屏加载)。

import { RcExcel, type RcExcelData } from '@stoly/react-component'

// 导出数据到 .xlsx
await RcExcel.export({
  header: [
    { header: '姓名', key: 'name' },
    { header: '年龄', key: 'age' },
  ],
  data: [{ name: '张三', age: 28 }],
}, '用户列表')

// 下载已有的 Blob 数据
RcExcel.downloadExcel(blob, '文件名')

Hooks

useSimpleReducer

轻量级 state 合并更新,类似 class 组件的 setState

const [state, dispatch, reset] = useSimpleReducer({ loading: false, count: 0 })

dispatch({ loading: true })   // 合并更新
reset()                       // 恢复初始值

useOnlyAsync

防止异步函数并发执行(上次未完成时忽略新的调用)。

const safeSubmit = useOnlyAsync(async () => {
  await submitForm()
})

usePage

分页状态管理。

const [pager, setPager] = usePage({ page: 1, size: 20 })
// pager: { page: number, size: number, total: number }
setPager({ total: 100 })

useRenderRef

ref + 触发重渲染的更新函数,兼顾同步读取和 React 响应式。

const [ref, setRef] = useRenderRef<string>('初始值')
ref.current        // 同步读取最新值
setRef('新值')     // 更新值并触发重渲染

类型导出

import type {
  RcBaseResult,         // BaseResult<T>: { success, data? }
  RcBaseResultData,     // NonNullable<T[K]>
  RcListPager,          // { page, size, total? }
  RcQueryData,          // { pageNum, pageSize, sort? }
  RcTableProps,
  RcTableRef,
  RcTableFormProps,
  RcModalProps,
  RcExcelData,
  RcLayoutHeaderProps,
  RcLayoutSiderProps,
  RcLayoutTabPageProps,
} from '@stoly/react-component'

注意事项

  1. 所有接口返回值必须包含 success: boolean 字段,组件通过此字段判断请求是否成功
  2. RcTableexported 功能仅适用于简单表头,复杂嵌套表头请直接使用 RcExcel.export()
  3. RcModal.confirm 传入 tableData 时会自动处理「删除最后一条数据后翻页到上一页」的逻辑
  4. 主题通过 styled-components 的 ThemeProvider 注入,包含 antd GlobalTokenprefixCls
  5. RcTable 不支持多字段排序,多列排序会提示错误

License

ISC