From 9b43b63648a571ab6b3b49feb9a8d2093a44ed1b Mon Sep 17 00:00:00 2001 From: afc163 Date: Fri, 26 Jun 2026 11:20:32 +0800 Subject: [PATCH 01/25] chore: standardize repository tooling --- .github/FUNDING.yml | 2 + .../workflows/cloudflare-pages-preview.yml | 38 +++ .github/workflows/codeql.yml | 22 +- .github/workflows/react-component-ci.yml | 2 +- .github/workflows/react-doctor.yml | 22 ++ .github/workflows/surge-preview.yml | 33 ++ README.md | 302 ++++++++++-------- package.json | 9 +- tsconfig.json | 3 +- vercel.json | 5 +- 10 files changed, 297 insertions(+), 141 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/cloudflare-pages-preview.yml create mode 100644 .github/workflows/react-doctor.yml create mode 100644 .github/workflows/surge-preview.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..758659af --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: ant-design +open_collective: ant-design diff --git a/.github/workflows/cloudflare-pages-preview.yml b/.github/workflows/cloudflare-pages-preview.yml new file mode 100644 index 00000000..c1738dfe --- /dev/null +++ b/.github/workflows/cloudflare-pages-preview.yml @@ -0,0 +1,38 @@ +name: Cloudflare Pages Preview + +on: + pull_request: + +permissions: + contents: read + deployments: write + +jobs: + preview: + runs-on: ubuntu-latest + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_PAGES_PROJECT: ${{ vars.CLOUDFLARE_PAGES_PROJECT }} + PREVIEW: true + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + with: + persist-credentials: false + - name: Skip Cloudflare Pages preview + if: ${{ env.CLOUDFLARE_API_TOKEN == '' || env.CLOUDFLARE_ACCOUNT_ID == '' || env.CLOUDFLARE_PAGES_PROJECT == '' }} + run: echo "Cloudflare Pages preview is not configured; skip deployment." + - name: Install dependencies + if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} + run: npm install + - name: Build site + if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} + run: npm run build + - name: Deploy preview + if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 + with: + apiToken: ${{ env.CLOUDFLARE_API_TOKEN }} + accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }} + command: pages deploy dist --project-name=${{ env.CLOUDFLARE_PAGES_PROJECT }} --branch=${{ github.head_ref }} + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d2a5f966..1375e7a4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,12 +1,12 @@ -name: "CodeQL" +name: 'CodeQL' on: push: - branches: [ "master" ] + branches: ['master'] pull_request: - branches: [ "master" ] + branches: ['master'] schedule: - - cron: "41 11 * * 2" + - cron: '41 11 * * 2' jobs: analyze: @@ -20,22 +20,24 @@ jobs: strategy: fail-fast: false matrix: - language: [ javascript ] + language: [javascript] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + with: + persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e with: - category: "/language:${{ matrix.language }}" + category: '/language:${{ matrix.language }}' diff --git a/.github/workflows/react-component-ci.yml b/.github/workflows/react-component-ci.yml index f860ff10..f8482b63 100644 --- a/.github/workflows/react-component-ci.yml +++ b/.github/workflows/react-component-ci.yml @@ -2,5 +2,5 @@ name: ✅ test on: [push, pull_request] jobs: test: - uses: react-component/rc-test/.github/workflows/test.yml@main + uses: react-component/rc-test/.github/workflows/test-utoo.yml@main secrets: inherit diff --git a/.github/workflows/react-doctor.yml b/.github/workflows/react-doctor.yml new file mode 100644 index 00000000..07884617 --- /dev/null +++ b/.github/workflows/react-doctor.yml @@ -0,0 +1,22 @@ +name: React Doctor + +on: + pull_request: + push: + branches: [master] + +permissions: + contents: read + pull-requests: write + issues: write + statuses: write + +jobs: + react-doctor: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + with: + fetch-depth: 0 + persist-credentials: false + - uses: millionco/react-doctor@0b4f4f4bd248a154e64eb508a48347f71154b3f3 diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml new file mode 100644 index 00000000..1f63ec71 --- /dev/null +++ b/.github/workflows/surge-preview.yml @@ -0,0 +1,33 @@ +name: Surge Preview + +on: + pull_request: + +permissions: + contents: read + pull-requests: write + checks: write + +jobs: + preview: + runs-on: ubuntu-latest + env: + SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + with: + persist-credentials: false + - uses: afc163/surge-preview@bf90a5a86111f6311ca42f0a5a0f80fb0fb03cec + if: ${{ env.SURGE_TOKEN != '' }} + with: + surge_token: ${{ env.SURGE_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} + dist: dist + failOnError: true + setCommitStatus: true + build: | + npm install + npm run build + - name: Skip Surge preview + if: ${{ env.SURGE_TOKEN == '' }} + run: echo "SURGE_TOKEN is not configured; skip Surge preview." diff --git a/README.md b/README.md index 59489d16..2d7c105c 100644 --- a/README.md +++ b/README.md @@ -1,140 +1,192 @@ -# @rc-component/tree-select - -React TreeSelect Component. - - -[![NPM version][npm-image]][npm-url] -[![npm download][download-image]][download-url] -[![build status][github-actions-image]][github-actions-url] -[![Codecov][codecov-image]][codecov-url] -[![bundle size][bundlephobia-image]][bundlephobia-url] -[![dumi][dumi-image]][dumi-url] - -[npm-image]: http://img.shields.io/npm/v/@rc-component/tree-select.svg?style=flat-square -[npm-url]: http://npmjs.org/package/@rc-component/tree-select -[travis-image]: https://img.shields.io/travis/react-component/tree-select/master?style=flat-square -[travis-url]: https://travis-ci.com/react-component/tree-select -[github-actions-image]: https://github.com/react-component/tree-select/actions/workflows/react-component-ci.yml/badge.svg -[github-actions-url]: https://github.com/react-component/tree-select/actions/workflows/react-component-ci.yml -[codecov-image]: https://img.shields.io/codecov/c/github/react-component/tree-select/master.svg?style=flat-square -[codecov-url]: https://app.codecov.io/gh/react-component/tree-select -[david-url]: https://david-dm.org/react-component/tree-select -[david-image]: https://david-dm.org/react-component/tree-select/status.svg?style=flat-square -[david-dev-url]: https://david-dm.org/react-component/tree-select?type=dev -[david-dev-image]: https://david-dm.org/react-component/tree-select/dev-status.svg?style=flat-square -[download-image]: https://img.shields.io/npm/dm/@rc-component/tree-select.svg?style=flat-square -[download-url]: https://npmjs.org/package/@rc-component/tree-select -[bundlephobia-url]: https://bundlephobia.com/package/@rc-component/tree-select -[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/@rc-component/tree-select -[dumi-url]: https://github.com/umijs/dumi -[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square - -## Screenshots - - - -## Development +
+

@rc-component/tree-select

+

🌳 React TreeSelect component for choosing values from tree data, with search, checkable nodes, async loading, and virtual scrolling.

+ +

+ NPM version + npm downloads + build status + Codecov + bundle size + dumi +

+
+ +

+ + + Ant Design + + Part of the Ant Design ecosystem. + +

+ +## Highlights + +| Area | Support | +| --------- | --------------------------------------------------------- | +| Data | Tree data, simple mode, custom field names | +| Selection | Single, multiple, checkable, strict check, label-in-value | +| Search | Controlled search, custom filter, auto clear | +| Loading | Async tree loading and controlled loaded keys | +| Scale | Virtual scrolling with configurable list metrics | + +## Install + +```bash +npm install @rc-component/tree-select +``` +## Usage + +```tsx | pure +import TreeSelect from '@rc-component/tree-select'; +import React from 'react'; +import { createRoot } from 'react-dom/client'; + +const treeData = [ + { + title: 'Parent', + value: 'parent', + children: [ + { + title: 'Child', + value: 'child', + }, + ], + }, +]; + +createRoot(document.getElementById('root')!).render( + , +); ``` + +## Examples + +```bash npm install npm start ``` -## Example +Open locally, or visit the online example: +. -http://localhost:8000/examples/ +## API -online example: https://tree-select-react-component.vercel.app/ +### TreeSelect + +TreeSelect also accepts public props from `@rc-component/select` `BaseSelect`, except +for the internal `mode`, `classNames`, `styles`, and `showSearch` props that are +redefined by TreeSelect. + +| Name | Description | Type | Default | +| ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | +| autoClearSearchValue | Deprecated. Use `showSearch.autoClearSearchValue` instead. | boolean | true | +| classNames | Semantic class names. | `Partial> & { popup?: Partial> }` | - | +| defaultValue | Initial selected value. | `ValueType` | - | +| fieldNames | Customize field names for tree data. | `FieldNames` | - | +| filterTreeNode | Deprecated. Use `showSearch.filterTreeNode` instead. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| inputValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | +| labelInValue | Whether to return labeled value objects instead of raw values. | boolean | false | +| listHeight | Popup list height. | number | 200 | +| listItemHeight | Popup list item height. | number | 20 | +| listItemScrollOffset | Popup list item scroll offset. | number | 0 | +| loadData | Load tree data asynchronously. | `(dataNode: LegacyDataNode) => Promise` | - | +| maxCount | Maximum selected item count in multiple or checkable mode. | number | - | +| multiple | Enable multiple selection. | boolean | false | +| onChange | Called when selected value changes. | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | +| onDeselect | Called when a value is deselected. | `(value: ValueType, option: OptionType) => void` | - | +| onPopupVisibleChange | Called when popup visibility changes. | `(open: boolean) => void` | - | +| onSearch | Deprecated. Use `showSearch.onSearch` instead. | `(value: string) => void` | - | +| onSelect | Called when a value is selected. | `(value: ValueType, option: OptionType) => void` | - | +| onTreeExpand | Called when expanded tree keys change. | `(expandedKeys: SafeKey[]) => void` | - | +| onTreeLoad | Called when async loaded keys change. | `(loadedKeys: SafeKey[]) => void` | - | +| searchValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | +| showCheckedStrategy | Configure how checked values are displayed. | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | `SHOW_CHILD` when `treeCheckable` is enabled, otherwise `SHOW_ALL` | +| showSearch | Enable search or configure search behavior. | boolean \| `SearchConfig` | - | +| showTreeIcon | Whether to show tree icons. | boolean | false | +| styles | Semantic styles. | `Partial> & { popup?: Partial> }` | - | +| switcherIcon | Custom tree switcher icon. | `IconType` | - | +| treeCheckable | Whether to show checkboxes in the tree. | boolean \| ReactNode | false | +| treeCheckStrictly | Check tree nodes precisely without parent-child association. | boolean | false | +| treeData | Tree node data. | `OptionType[]` | - | +| treeDataSimpleMode | Enable simple tree data mode. | boolean \| `SimpleModeConfig` | false | +| treeDefaultExpandAll | Expand all tree nodes by default. | boolean | false | +| treeDefaultExpandedKeys | Initial expanded tree keys. | `SafeKey[]` | - | +| treeExpandAction | Expand action for tree nodes. | false \| `click` \| `doubleClick` | `click` | +| treeExpandedKeys | Controlled expanded tree keys. | `SafeKey[]` | - | +| treeIcon | Custom tree icon. | `IconType` | - | +| treeLine | Whether to show tree lines. | boolean | false | +| treeLoadedKeys | Controlled loaded tree keys. | `SafeKey[]` | - | +| treeMotion | Tree motion config. | any | - | +| treeNodeFilterProp | Deprecated. Use `showSearch.treeNodeFilterProp` instead. | string | `value` | +| treeNodeLabelProp | Tree node prop rendered as selected label. | string | `title` | +| treeTitleRender | Custom tree node title renderer. | `(node: OptionType) => ReactNode` | - | +| value | Controlled selected value. | `ValueType` | - | +| virtual | Disable virtual scrolling when set to `false`. | boolean | - | + +### SearchConfig + +| Name | Description | Type | Default | +| -------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- | +| autoClearSearchValue | Clear search input after selecting or deselecting in multiple mode. | boolean | true | +| filterTreeNode | Filter tree nodes by search input. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| onSearch | Called when search input changes. | `(value: string) => void` | - | +| searchValue | Controlled search input value. | string | - | +| treeNodeFilterProp | Tree node prop used for filtering when `filterTreeNode` is enabled. | string | `value` | + +### DataNode + +| Name | Description | Type | Default | +| -------- | ---------------------- | ------------ | ------- | +| children | Child tree nodes. | `DataNode[]` | - | +| disabled | Disable the tree node. | boolean | false | +| key | Unique tree node key. | `React.Key` | - | +| title | Tree node title. | ReactNode | - | +| value | Tree node value. | `SafeKey` | - | + +### TreeNode + +Using `treeData` is recommended. `TreeNode` is kept for legacy usage. + +| Name | Description | Type | Default | +| -------- | ----------------------------- | --------- | ------- | +| disabled | Disable the tree node. | boolean | false | +| isLeaf | Mark the node as a leaf node. | boolean | false | +| key | Unique tree node key. | React.Key | - | +| title | Tree node title. | ReactNode | - | +| value | Tree node value. | SafeKey | - | + +## Notes + +For large trees, avoid expanding all nodes by default. Prefer virtual scrolling, +keep the number of simultaneous TreeSelect instances low, and use +`treeCheckStrictly` when checkable mode has many nodes. + +In `treeCheckable` mode, removing a selected item from the selector and +unchecking the matching tree node produce the same selected values, but they are +different interactions. Both trigger `onChange`, and the `extra` argument may +therefore differ. -## install +## Development -[![@rc-component/tree-select](https://nodei.co/npm/@rc-component/tree-select.png)](https://npmjs.org/package/@rc-component/tree-select) +```bash +npm install +npm start +npm test +npm run lint +npm run compile +``` -## API +## Release + +```bash +npm publish +``` -### TreeSelect props - -| name | description | type | default | -| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- | -| className | additional css class of root dom node | String | '' | -| prefixCls | prefix class | String | '' | -| animation | dropdown animation name. only support slide-up now | String | '' | -| transitionName | dropdown css animation name | String | '' | -| choiceTransitionName | css animation name for selected items at multiple mode | String | '' | -| popupMatchSelectWidth | whether dropdown's with is same with select. Default set `min-width` same as input | bool | true | -| dropdownClassName | additional className applied to dropdown | String | - | -| dropdownStyle | additional style applied to dropdown | Object | {} | -| onPopupVisibleChange | control dropdown visible | function | `() => { return true; }` | -| notFoundContent | specify content to show when no result matches. | String | 'Not Found' | -| showSearch | whether show search input in single mode | bool | true | -| allowClear | whether allowClear | bool | false | -| maxTagTextLength | max tag text length to show | number | - | -| maxTagCount | max tag count to show | number | - | -| maxCount | Limit the maximum number of items that can be selected in multiple mode | number | - | -| maxTagPlaceholder | placeholder for omitted values | ReactNode/function(omittedValues) | - | -| multiple | whether multiple select (true when enable treeCheckable) | bool | false | -| disabled | whether disabled select | bool | false | -| searchValue | work with `onSearch` to make search value controlled. | string | '' | -| defaultValue | initial selected treeNode(s) | same as value type | - | -| value | current selected treeNode(s). | normal: String/Array. labelInValue: {value:String,label:React.Node}/Array<{value,label}>. treeCheckStrictly(halfChecked default false): {value:String,label:React.Node, halfChecked}/Array<{value,label,halfChecked}>. | - | -| labelInValue | whether to embed label in value, see above value type | Bool | false | -| onChange | called when select treeNode or input value change | function(value, label(null), extra) | - | -| onSelect | called when select treeNode | function(value, node, extra) | - | -| onSearch | called when input changed | function | - | -| onTreeExpand | called when tree node expand | function(expandedKeys) | - | -| onPopupScroll | called when popup scroll | function(event) | - | -| showCheckedStrategy | `TreeSelect.SHOW_ALL`: show all checked treeNodes (Include parent treeNode). `TreeSelect.SHOW_PARENT`: show checked treeNodes (Just show parent treeNode). Default just show child. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD | -| treeIcon | show tree icon | bool | false | -| treeLine | show tree line | bool | false | -| treeDefaultExpandAll | default expand all treeNode | bool | false | -| treeDefaultExpandedKeys | default expanded treeNode keys | Array | - | -| treeExpandedKeys | set tree expanded keys | Array | - | -| treeExpandAction | Tree open logic, optional: false \| `click` \| `doubleClick`, same as `expandAction` of `rc-tree` | string \| boolean | `click` | -| treeCheckable | whether tree show checkbox (select callback will not fire) | bool | false | -| treeCheckStrictly | check node precisely, parent and children nodes are not associated | bool | false | -| filterTreeNode | whether filter treeNodes by input value. default filter by treeNode's treeNodeFilterProp prop's value | bool/Function(inputValue:string, treeNode:TreeNode) | Function | -| treeNodeFilterProp | which prop value of treeNode will be used for filter if filterTreeNode return true | String | 'value' | -| treeNodeLabelProp | which prop value of treeNode will render as content of select | String | 'title' | -| treeData | treeNodes data Array, if set it then you need not to construct children TreeNode. (value should be unique across the whole array) | array<{value,label,children, [disabled,selectable]}> | [] | -| treeDataSimpleMode | enable simple mode of treeData.(treeData should be like this: [{id:1, pId:0, value:'1', label:"test1",...},...], `pId` is parent node's id) | bool/object{id:'id', pId:'pId', rootPId:null} | false | -| treeTitleRender | Custom render nodes | (nodeData: OptionType) => ReactNode | -| loadData | load data asynchronously | function(node) | - | -| getPopupContainer | container which popup select menu rendered into | function(trigger:Node):Node | function(){return document.body;} | -| autoClearSearchValue | auto clear search input value when multiple select is selected/deselected | boolean | true | -| suffixIcon | specify the select arrow icon | ReactNode \| (props: TreeProps) => ReactNode | - | -| clearIcon | specify the clear icon | ReactNode \| (props: TreeProps) => ReactNode | - | -| removeIcon | specify the remove icon | ReactNode \| (props: TreeProps) => ReactNode | - | -| switcherIcon | specify the switcher icon | ReactNode \| (props: TreeProps) => ReactNode | - | -| virtual | Disable virtual when `false` | false | - | - -### TreeNode props - -> note: you'd better to use `treeData` instead of using TreeNode. - -| name | description | type | default | -| -------- | ------------------------------------------------------------------------- | -------------- | ------- | -| disabled | disable treeNode | bool | false | -| key | it's value must be unique across the tree's all TreeNode, you must set it | String | - | -| value | default as treeNodeFilterProp (be unique across the tree's all TreeNode) | String | '' | -| title | tree/subTree's title | String/element | '---' | -| isLeaf | whether it's leaf node | bool | false | - -## note - -1. Optimization tips(when there are large amounts of data, like more than 5000 nodes) - - Do not Expand all nodes. - - Recommend not exist many `TreeSelect` components in a page at the same time. - - Recommend not use `treeCheckable` mode, or use `treeCheckStrictly`. -2. In `treeCheckable` mode, It has the same effect when click `x`(node in Selection box) or uncheck in the treeNode(in dropdown panel), but the essence is not the same. So, even if both of them trigger `onChange` method, but the parameters (the third parameter) are different. (中文:在`treeCheckable`模式下,已选择节点上的`x`删除操作、和相应 treeNode 节点上 checkbox 的 uncheck 操作,最终效果相同,但本质不一样。前者跟弹出的 tree 组件可以“毫无关系”(例如 dropdown 没展开过,tree 也就没渲染好),而后者是 tree 组件上的节点 uncheck 事件。所以、即便两者都会触发`onChange`方法、但它们的参数(第三个参数)是不同的。) - -## Test Case - -http://localhost:8000/tests/runner.html?coverage - -## Coverage - -http://localhost:8000/node_modules/rc-server/node_modules/node-jscover/lib/front-end/jscoverage.html?w=http://localhost:8000/tests/runner.html?coverage +The `prepublishOnly` script runs `npm run compile && rc-np` before publishing. ## License -@rc-component/tree-select is released under the MIT license. +`@rc-component/tree-select` is released under the MIT license. diff --git a/package.json b/package.json index d49e2295..944371fa 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,10 @@ "now-build": "npm run build", "prepare": "husky && dumi setup", "prepublishOnly": "npm run compile && rc-np", - "prettier": "prettier '{src,tests}/**/*.{ts,tsx}' 'tests/**/*.js' --write", + "prettier": "prettier --write --ignore-unknown .", "start": "dumi dev", - "test": "rc-test" + "test": "rc-test", + "tsc": "tsc --noEmit" }, "lint-staged": { "*": "prettier --write --ignore-unknown" @@ -61,11 +62,13 @@ "@types/react": "^18.3.11", "@types/react-dom": "^18.0.0", "@types/warning": "^3.0.3", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "@umijs/fabric": "^4.0.1", "cross-env": "^7.0.3", "dumi": "^2.4.12", "eslint": "^8.57.1", - "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-unicorn": "^56.0.0", "father": "^4.5.0", "glob": "^11.0.0", diff --git a/tsconfig.json b/tsconfig.json index a0d29f04..b233ccba 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,5 +12,6 @@ "@@/*": [".dumi/tmp/*"], "@rc-component/tree-select": ["src/index.tsx"] } - } + }, + "include": [".dumirc.ts", ".fatherrc.ts", "src", "tests", "examples"] } diff --git a/vercel.json b/vercel.json index cc12e405..e884e1b3 100644 --- a/vercel.json +++ b/vercel.json @@ -1,3 +1,6 @@ { - "framework": "umijs" + "framework": "umijs", + "installCommand": "npm install", + "buildCommand": "npm run build", + "outputDirectory": "dist" } From a82e792260c19be25d4d3a029f18db149ae94eaf Mon Sep 17 00:00:00 2001 From: afc163 Date: Fri, 26 Jun 2026 15:04:34 +0800 Subject: [PATCH 02/25] chore: remove cloudflare preview and now-build --- .../workflows/cloudflare-pages-preview.yml | 38 ------------------- package.json | 1 - 2 files changed, 39 deletions(-) delete mode 100644 .github/workflows/cloudflare-pages-preview.yml diff --git a/.github/workflows/cloudflare-pages-preview.yml b/.github/workflows/cloudflare-pages-preview.yml deleted file mode 100644 index c1738dfe..00000000 --- a/.github/workflows/cloudflare-pages-preview.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Cloudflare Pages Preview - -on: - pull_request: - -permissions: - contents: read - deployments: write - -jobs: - preview: - runs-on: ubuntu-latest - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - CLOUDFLARE_PAGES_PROJECT: ${{ vars.CLOUDFLARE_PAGES_PROJECT }} - PREVIEW: true - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - with: - persist-credentials: false - - name: Skip Cloudflare Pages preview - if: ${{ env.CLOUDFLARE_API_TOKEN == '' || env.CLOUDFLARE_ACCOUNT_ID == '' || env.CLOUDFLARE_PAGES_PROJECT == '' }} - run: echo "Cloudflare Pages preview is not configured; skip deployment." - - name: Install dependencies - if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} - run: npm install - - name: Build site - if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} - run: npm run build - - name: Deploy preview - if: ${{ env.CLOUDFLARE_API_TOKEN != '' && env.CLOUDFLARE_ACCOUNT_ID != '' && env.CLOUDFLARE_PAGES_PROJECT != '' }} - uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 - with: - apiToken: ${{ env.CLOUDFLARE_API_TOKEN }} - accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy dist --project-name=${{ env.CLOUDFLARE_PAGES_PROJECT }} --branch=${{ github.head_ref }} - gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 944371fa..2c39dbd9 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "build": "dumi build", "compile": "father build", "lint": "eslint src/ examples/ --ext .tsx,.ts,.jsx,.js", - "now-build": "npm run build", "prepare": "husky && dumi setup", "prepublishOnly": "npm run compile && rc-np", "prettier": "prettier --write --ignore-unknown .", From 7276e85374a64e7159b4a7206f6f3b2612f38871 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 00:42:57 +0800 Subject: [PATCH 03/25] docs: add Ant Design logo to README header --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2d7c105c..576c57d2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@

@rc-component/tree-select

+ Ant Design

🌳 React TreeSelect component for choosing values from tree data, with search, checkable nodes, async loading, and virtual scrolling.

From 8c4c4cbbd40a30d918942da7a376ec07d90bd458 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 01:59:35 +0800 Subject: [PATCH 04/25] docs: standardize README release details --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 576c57d2..2d77d959 100644 --- a/README.md +++ b/README.md @@ -183,11 +183,11 @@ npm run compile ## Release ```bash -npm publish +npm run prepublishOnly ``` -The `prepublishOnly` script runs `npm run compile && rc-np` before publishing. +The release flow is handled by `@rc-component/np` through the `rc-np` command after the package build. ## License -`@rc-component/tree-select` is released under the MIT license. +@rc-component/tree-select is released under the [MIT](./LICENSE.md) license. From 89bd72571ff56825182aa10e298c94513f7ab2bf Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 02:13:59 +0800 Subject: [PATCH 05/25] ci: make surge preview non-blocking --- .github/workflows/surge-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index 1f63ec71..da133488 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -23,7 +23,7 @@ jobs: surge_token: ${{ env.SURGE_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} dist: dist - failOnError: true + failOnError: false setCommitStatus: true build: | npm install From f0220274c041aa65fc1d5c7f4d3c1dd98e962c17 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 02:17:45 +0800 Subject: [PATCH 06/25] docs: clarify Ant Design ecosystem note --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d77d959..733c7c42 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Ant Design - Part of the Ant Design ecosystem. + Part of the Ant Design ecosystem.

From 419097c261567a2672eddd6f54b0fe177be89f68 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 02:25:43 +0800 Subject: [PATCH 07/25] ci: keep surge preview as fallback --- .github/workflows/surge-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index da133488..777206d3 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -24,7 +24,7 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} dist: dist failOnError: false - setCommitStatus: true + setCommitStatus: false build: | npm install npm run build From e50f457b2ef4ca70a6b822702d1cc2ccfb5bc480 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 13:04:05 +0800 Subject: [PATCH 08/25] docs: refine README usage and ecosystem note --- README.md | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 733c7c42..ed268894 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@

@rc-component/tree-select

+

Part of the Ant Design ecosystem.

Ant Design

🌳 React TreeSelect component for choosing values from tree data, with search, checkable nodes, async loading, and virtual scrolling.

@@ -13,14 +14,6 @@

-

- - - Ant Design - - Part of the Ant Design ecosystem. - -

## Highlights @@ -42,8 +35,6 @@ npm install @rc-component/tree-select ```tsx | pure import TreeSelect from '@rc-component/tree-select'; -import React from 'react'; -import { createRoot } from 'react-dom/client'; const treeData = [ { @@ -58,9 +49,7 @@ const treeData = [ }, ]; -createRoot(document.getElementById('root')!).render( - , -); +export default () => ; ``` ## Examples From b1ec1885211e9da17ffee1834ef277c11cd3edff Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 13:22:21 +0800 Subject: [PATCH 09/25] ci: isolate surge preview token --- .github/workflows/surge-preview.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index 777206d3..30f70a85 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -11,23 +11,25 @@ permissions: jobs: preview: runs-on: ubuntu-latest - env: - SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: persist-credentials: false + - name: Build preview + if: ${{ secrets.SURGE_TOKEN != '' }} + run: | + npm install + npm run build - uses: afc163/surge-preview@bf90a5a86111f6311ca42f0a5a0f80fb0fb03cec - if: ${{ env.SURGE_TOKEN != '' }} + if: ${{ secrets.SURGE_TOKEN != '' }} + env: + SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} with: surge_token: ${{ env.SURGE_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} dist: dist failOnError: false setCommitStatus: false - build: | - npm install - npm run build - name: Skip Surge preview - if: ${{ env.SURGE_TOKEN == '' }} + if: ${{ secrets.SURGE_TOKEN == '' }} run: echo "SURGE_TOKEN is not configured; skip Surge preview." From 34f4c911a372773daf19ddb308368a6db397f100 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 22:01:17 +0800 Subject: [PATCH 10/25] docs: update Ant Design logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed268894..912cc190 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

@rc-component/tree-select

Part of the Ant Design ecosystem.

- Ant Design + Ant Design

🌳 React TreeSelect component for choosing values from tree data, with search, checkable nodes, async loading, and virtual scrolling.

From 77fadf099d7aa9e28f785449bd40eaf1c7ddee52 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 22:20:31 +0800 Subject: [PATCH 11/25] docs: add Chinese README --- README.md | 2 + README.zh-CN.md | 184 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 README.zh-CN.md diff --git a/README.md b/README.md index 912cc190..ab5c8a21 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@

+

English | 简体中文

+ ## Highlights diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 00000000..547ff525 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,184 @@ +
+

@rc-component/tree-select

+

Ant Design 生态的一部分。

+ Ant Design +

🌲 React 树选择组件,结合树形数据、多选、搜索和下拉交互。

+ +

+ NPM version + npm downloads + build status + Codecov + bundle size + dumi +

+
+ +

English | 简体中文

+ + +## 特性 + +| 范围 | 支持 | +| --------- | --------------------------------------------------------- | +| Data | Tree data, simple mode, custom field names | +| Selection | Single, multiple, checkable, strict check, label-in-value | +| Search | Controlled search, custom filter, auto clear | +| Loading | Async tree loading and controlled loaded keys | +| Scale | Virtual scrolling with configurable list metrics | + +## 安装 + +```bash +npm install @rc-component/tree-select +``` + +## 使用 + +```tsx | pure +import TreeSelect from '@rc-component/tree-select'; + +const treeData = [ + { + title: 'Parent', + value: 'parent', + children: [ + { + title: 'Child', + value: 'child', + }, + ], + }, +]; + +export default () => ; +``` + +## 示例 + +```bash +npm install +npm start +``` + +Open locally, or visit the online example: +. + +## API + +### TreeSelect + +TreeSelect also accepts public props from `@rc-component/select` `BaseSelect`, except +for the internal `mode`, `classNames`, `styles`, and `showSearch` props that are +redefined by TreeSelect. + +| 名称 | 说明 | 类型 | 默认值 | +| ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | +| autoClearSearchValue | Deprecated. Use `showSearch.autoClearSearchValue` instead. | boolean | true | +| classNames | Semantic class names. | `Partial> & { popup?: Partial> }` | - | +| defaultValue | Initial selected value. | `ValueType` | - | +| fieldNames | Customize field names for tree data. | `FieldNames` | - | +| filterTreeNode | Deprecated. Use `showSearch.filterTreeNode` instead. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| inputValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | +| labelInValue | Whether to return labeled value objects instead of raw values. | boolean | false | +| listHeight | Popup list height. | number | 200 | +| listItemHeight | Popup list item height. | number | 20 | +| listItemScrollOffset | Popup list item scroll offset. | number | 0 | +| loadData | Load tree data asynchronously. | `(dataNode: LegacyDataNode) => Promise` | - | +| maxCount | Maximum selected item count in multiple or checkable mode. | number | - | +| multiple | Enable multiple selection. | boolean | false | +| onChange | Called when selected value changes. | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | +| onDeselect | Called when a value is deselected. | `(value: ValueType, option: OptionType) => void` | - | +| onPopupVisibleChange | Called when popup visibility changes. | `(open: boolean) => void` | - | +| onSearch | Deprecated. Use `showSearch.onSearch` instead. | `(value: string) => void` | - | +| onSelect | Called when a value is selected. | `(value: ValueType, option: OptionType) => void` | - | +| onTreeExpand | Called when expanded tree keys change. | `(expandedKeys: SafeKey[]) => void` | - | +| onTreeLoad | Called when async loaded keys change. | `(loadedKeys: SafeKey[]) => void` | - | +| searchValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | +| showCheckedStrategy | Configure how checked values are displayed. | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | `SHOW_CHILD` when `treeCheckable` is enabled, otherwise `SHOW_ALL` | +| showSearch | Enable search or configure search behavior. | boolean \| `SearchConfig` | - | +| showTreeIcon | Whether to show tree icons. | boolean | false | +| styles | Semantic styles. | `Partial> & { popup?: Partial> }` | - | +| switcherIcon | Custom tree switcher icon. | `IconType` | - | +| treeCheckable | Whether to show checkboxes in the tree. | boolean \| ReactNode | false | +| treeCheckStrictly | Check tree nodes precisely without parent-child association. | boolean | false | +| treeData | Tree node data. | `OptionType[]` | - | +| treeDataSimpleMode | Enable simple tree data mode. | boolean \| `SimpleModeConfig` | false | +| treeDefaultExpandAll | Expand all tree nodes by default. | boolean | false | +| treeDefaultExpandedKeys | Initial expanded tree keys. | `SafeKey[]` | - | +| treeExpandAction | Expand action for tree nodes. | false \| `click` \| `doubleClick` | `click` | +| treeExpandedKeys | Controlled expanded tree keys. | `SafeKey[]` | - | +| treeIcon | Custom tree icon. | `IconType` | - | +| treeLine | Whether to show tree lines. | boolean | false | +| treeLoadedKeys | Controlled loaded tree keys. | `SafeKey[]` | - | +| treeMotion | Tree motion config. | any | - | +| treeNodeFilterProp | Deprecated. Use `showSearch.treeNodeFilterProp` instead. | string | `value` | +| treeNodeLabelProp | Tree node prop rendered as selected label. | string | `title` | +| treeTitleRender | Custom tree node title renderer. | `(node: OptionType) => ReactNode` | - | +| value | Controlled selected value. | `ValueType` | - | +| virtual | Disable virtual scrolling when set to `false`. | boolean | - | + +### SearchConfig + +| 名称 | 说明 | 类型 | 默认值 | +| -------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- | +| autoClearSearchValue | Clear search input after selecting or deselecting in multiple mode. | boolean | true | +| filterTreeNode | Filter tree nodes by search input. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| onSearch | Called when search input changes. | `(value: string) => void` | - | +| searchValue | Controlled search input value. | string | - | +| treeNodeFilterProp | Tree node prop used for filtering when `filterTreeNode` is enabled. | string | `value` | + +### DataNode + +| 名称 | 说明 | 类型 | 默认值 | +| -------- | ---------------------- | ------------ | ------- | +| children | Child tree nodes. | `DataNode[]` | - | +| disabled | Disable the tree node. | boolean | false | +| key | Unique tree node key. | `React.Key` | - | +| title | Tree node title. | ReactNode | - | +| value | Tree node value. | `SafeKey` | - | + +### TreeNode + +Using `treeData` is recommended. `TreeNode` is kept for legacy usage. + +| 名称 | 说明 | 类型 | 默认值 | +| -------- | ----------------------------- | --------- | ------- | +| disabled | Disable the tree node. | boolean | false | +| isLeaf | Mark the node as a leaf node. | boolean | false | +| key | Unique tree node key. | React.Key | - | +| title | Tree node title. | ReactNode | - | +| value | Tree node value. | SafeKey | - | + +## 说明 + +For large trees, avoid expanding all nodes by default. Prefer virtual scrolling, +keep the number of simultaneous TreeSelect instances low, and use +`treeCheckStrictly` when checkable mode has many nodes. + +In `treeCheckable` mode, removing a selected item from the selector and +unchecking the matching tree node produce the same selected values, but they are +different interactions. Both trigger `onChange`, and the `extra` argument may +therefore differ. + +## 本地开发 + +```bash +npm install +npm start +npm test +npm run lint +npm run compile +``` + +## 发布 + +```bash +npm run prepublishOnly +``` + +The release flow is handled by `@rc-component/np` through the `rc-np` command after the package build. + +## 许可证 + +@rc-component/tree-select is released under the [MIT](./LICENSE.md) license. From 983ba8bdf3d7b9777ab6f976e1936343fc422c03 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 27 Jun 2026 23:04:16 +0800 Subject: [PATCH 12/25] docs: refine bilingual README branding --- README.md | 3 +- README.zh-CN.md | 152 +++++++++++++++++++++++------------------------- 2 files changed, 73 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index ab5c8a21..1e57bd2f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@

@rc-component/tree-select

-

Part of the Ant Design ecosystem.

- Ant Design +

Ant Design Part of the Ant Design ecosystem.

🌳 React TreeSelect component for choosing values from tree data, with search, checkable nodes, async loading, and virtual scrolling.

diff --git a/README.zh-CN.md b/README.zh-CN.md index 547ff525..219ff8f4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,8 +1,7 @@

@rc-component/tree-select

-

Ant Design 生态的一部分。

- Ant Design -

🌲 React 树选择组件,结合树形数据、多选、搜索和下拉交互。

+

Ant Design Ant Design 生态的一部分。

+

🌳 React 树选择组件,结合树形数据、多选、搜索和下拉交互。

NPM version @@ -21,11 +20,11 @@ | 范围 | 支持 | | --------- | --------------------------------------------------------- | -| Data | Tree data, simple mode, custom field names | -| Selection | Single, multiple, checkable, strict check, label-in-value | -| Search | Controlled search, custom filter, auto clear | -| Loading | Async tree loading and controlled loaded keys | -| Scale | Virtual scrolling with configurable list metrics | +| 数据 | 树数据、简单模式和自定义字段名 | +| 选择 | 单选、多选、勾选、严格勾选和标注值 | +| 搜索 | 受控搜索、自定义过滤和自动清除 | +| 加载 | 异步树加载和受控 loaded keys | +| 规模 | 支持可配置列表指标的虚拟滚动 | ## 安装 @@ -61,104 +60,97 @@ npm install npm start ``` -Open locally, or visit the online example: -. +本地打开 ,或访问在线示例:。 ## API ### TreeSelect -TreeSelect also accepts public props from `@rc-component/select` `BaseSelect`, except -for the internal `mode`, `classNames`, `styles`, and `showSearch` props that are -redefined by TreeSelect. +TreeSelect 还接受来自 `@rc-component/select` `BaseSelect` 的公共属性,但内部使用的 `mode`、`classNames`、`styles` 和由 TreeSelect 重新定义的 `showSearch` 除外。 | 名称 | 说明 | 类型 | 默认值 | | ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | -| autoClearSearchValue | Deprecated. Use `showSearch.autoClearSearchValue` instead. | boolean | true | -| classNames | Semantic class names. | `Partial> & { popup?: Partial> }` | - | -| defaultValue | Initial selected value. | `ValueType` | - | -| fieldNames | Customize field names for tree data. | `FieldNames` | - | -| filterTreeNode | Deprecated. Use `showSearch.filterTreeNode` instead. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | -| inputValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | -| labelInValue | Whether to return labeled value objects instead of raw values. | boolean | false | -| listHeight | Popup list height. | number | 200 | -| listItemHeight | Popup list item height. | number | 20 | -| listItemScrollOffset | Popup list item scroll offset. | number | 0 | -| loadData | Load tree data asynchronously. | `(dataNode: LegacyDataNode) => Promise` | - | -| maxCount | Maximum selected item count in multiple or checkable mode. | number | - | -| multiple | Enable multiple selection. | boolean | false | -| onChange | Called when selected value changes. | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | -| onDeselect | Called when a value is deselected. | `(value: ValueType, option: OptionType) => void` | - | -| onPopupVisibleChange | Called when popup visibility changes. | `(open: boolean) => void` | - | -| onSearch | Deprecated. Use `showSearch.onSearch` instead. | `(value: string) => void` | - | -| onSelect | Called when a value is selected. | `(value: ValueType, option: OptionType) => void` | - | -| onTreeExpand | Called when expanded tree keys change. | `(expandedKeys: SafeKey[]) => void` | - | -| onTreeLoad | Called when async loaded keys change. | `(loadedKeys: SafeKey[]) => void` | - | -| searchValue | Deprecated. Use `showSearch.searchValue` instead. | string | - | -| showCheckedStrategy | Configure how checked values are displayed. | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | `SHOW_CHILD` when `treeCheckable` is enabled, otherwise `SHOW_ALL` | -| showSearch | Enable search or configure search behavior. | boolean \| `SearchConfig` | - | -| showTreeIcon | Whether to show tree icons. | boolean | false | -| styles | Semantic styles. | `Partial> & { popup?: Partial> }` | - | -| switcherIcon | Custom tree switcher icon. | `IconType` | - | -| treeCheckable | Whether to show checkboxes in the tree. | boolean \| ReactNode | false | -| treeCheckStrictly | Check tree nodes precisely without parent-child association. | boolean | false | -| treeData | Tree node data. | `OptionType[]` | - | -| treeDataSimpleMode | Enable simple tree data mode. | boolean \| `SimpleModeConfig` | false | -| treeDefaultExpandAll | Expand all tree nodes by default. | boolean | false | -| treeDefaultExpandedKeys | Initial expanded tree keys. | `SafeKey[]` | - | -| treeExpandAction | Expand action for tree nodes. | false \| `click` \| `doubleClick` | `click` | -| treeExpandedKeys | Controlled expanded tree keys. | `SafeKey[]` | - | -| treeIcon | Custom tree icon. | `IconType` | - | -| treeLine | Whether to show tree lines. | boolean | false | -| treeLoadedKeys | Controlled loaded tree keys. | `SafeKey[]` | - | -| treeMotion | Tree motion config. | any | - | -| treeNodeFilterProp | Deprecated. Use `showSearch.treeNodeFilterProp` instead. | string | `value` | -| treeNodeLabelProp | Tree node prop rendered as selected label. | string | `title` | -| treeTitleRender | Custom tree node title renderer. | `(node: OptionType) => ReactNode` | - | -| value | Controlled selected value. | `ValueType` | - | -| virtual | Disable virtual scrolling when set to `false`. | boolean | - | +| autoClearSearchValue | 已弃用。请改用 `showSearch.autoClearSearchValue`。 | boolean | true | +| classNames | 语义className。 | `Partial> & { popup?: Partial> }` | - | +| defaultValue | 初始选中值。 | `ValueType` | - | +| fieldNames | 自定义树数据的字段名称。 | `FieldNames` | - | +| filterTreeNode | 已弃用。请改用 `showSearch.filterTreeNode`。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| inputValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | +| labelInValue | 是否返回标记值对象而不是原始值。 | boolean | false | +| listHeight | 弹层列表高度。 | number | 200 | +| listItemHeight | 弹层列表项的高度。 | number | 20 | +| listItemScrollOffset | 弹层列表项滚动偏移。 | number | 0 | +| loadData | 异步加载树数据。 | `(dataNode: LegacyDataNode) => Promise` | - | +| maxCount | 多重或可检查模式下的最大选定项目数。 | number | - | +| multiple | 启用多项选择。 | boolean | false | +| onChange | 当选定值更改时调用。 | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | +| onDeselect | 当取消选择某个值时调用。 | `(value: ValueType, option: OptionType) => void` | - | +| onPopupVisibleChange | 当弹层窗口可见性发生变化时调用。 | `(open: boolean) => void` | - | +| onSearch | 已弃用。请改用 `showSearch.onSearch`。 | `(value: string) => void` | - | +| onSelect | 选择值时调用。 | `(value: ValueType, option: OptionType) => void` | - | +| onTreeExpand | 当扩展树键更改时调用。 | `(expandedKeys: SafeKey[]) => void` | - | +| onTreeLoad | 当异步加载的键发生变化时调用。 | `(loadedKeys: SafeKey[]) => void` | - | +| searchValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | +| showCheckedStrategy | 配置检查值的显示方式。 | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | 当 `treeCheckable` 使能时为 `SHOW_CHILD`,否则为 `SHOW_ALL` | +| showSearch | 启用搜索或配置搜索行为。 | boolean \| `SearchConfig` | - | +| showTreeIcon | 是否显示树形图标。 | boolean | false | +| styles | 语义化样式。 | `Partial> & { popup?: Partial> }` | - | +| switcherIcon | 自定义树切换器图标。 | `IconType` | - | +| treeCheckable | 是否在树中显示复选框。 | boolean \| ReactNode | false | +| treeCheckStrictly | 精确检查树节点,无需父子关联。 | boolean | false | +| treeData | 树节点数据。 | `OptionType[]` | - | +| treeDataSimpleMode | 启用简单树数据模式。 | boolean \| `SimpleModeConfig` | false | +| treeDefaultExpandAll | 默认展开所有树节点。 | boolean | false | +| treeDefaultExpandedKeys | 初始扩展树键。 | `SafeKey[]` | - | +| treeExpandAction | 树节点展开触发行为。 | false \| `click` \| `doubleClick` | `click` | +| treeExpandedKeys | 受控的扩展树键。 | `SafeKey[]` | - | +| treeIcon | 自定义树图标。 | `IconType` | - | +| treeLine | 是否显示树线。 | boolean | false | +| treeLoadedKeys | 受控加载的树键。 | `SafeKey[]` | - | +| treeMotion | 树运动配置。 | any | - | +| treeNodeFilterProp | 已弃用。请改用 `showSearch.treeNodeFilterProp`。 | string | `value` | +| treeNodeLabelProp | 作为选中标签渲染的树节点属性。 | string | `title` | +| treeTitleRender | 自定义树节点标题渲染器。 | `(node: OptionType) => ReactNode` | - | +| value | 受控选中值。 | `ValueType` | - | +| virtual | 设置为 `false` 时禁用虚拟滚动。 | boolean | - | ### SearchConfig | 名称 | 说明 | 类型 | 默认值 | | -------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- | -| autoClearSearchValue | Clear search input after selecting or deselecting in multiple mode. | boolean | true | -| filterTreeNode | Filter tree nodes by search input. | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | -| onSearch | Called when search input changes. | `(value: string) => void` | - | -| searchValue | Controlled search input value. | string | - | -| treeNodeFilterProp | Tree node prop used for filtering when `filterTreeNode` is enabled. | string | `value` | +| autoClearSearchValue | 在多种模式下选择或取消选择后清除搜索输入。 | boolean | true | +| filterTreeNode | 根据搜索输入过滤树节点。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| onSearch | 当搜索输入更改时调用。 | `(value: string) => void` | - | +| searchValue | 受控搜索输入值。 | string | - | +| treeNodeFilterProp | 启用 `filterTreeNode` 时用于过滤的树节点属性。 | string | `value` | ### DataNode | 名称 | 说明 | 类型 | 默认值 | | -------- | ---------------------- | ------------ | ------- | -| children | Child tree nodes. | `DataNode[]` | - | -| disabled | Disable the tree node. | boolean | false | -| key | Unique tree node key. | `React.Key` | - | -| title | Tree node title. | ReactNode | - | -| value | Tree node value. | `SafeKey` | - | +| children | 子树节点。 | `DataNode[]` | - | +| disabled | 禁用树节点。 | boolean | false | +| key | 唯一树节点 key。 | `React.Key` | - | +| title | 树节点标题。 | ReactNode | - | +| value | 树节点值。 | `SafeKey` | - | ### TreeNode -Using `treeData` is recommended. `TreeNode` is kept for legacy usage. +推荐使用 `treeData`。`TreeNode` 仅为兼容旧用法保留。 | 名称 | 说明 | 类型 | 默认值 | | -------- | ----------------------------- | --------- | ------- | -| disabled | Disable the tree node. | boolean | false | -| isLeaf | Mark the node as a leaf node. | boolean | false | -| key | Unique tree node key. | React.Key | - | -| title | Tree node title. | ReactNode | - | -| value | Tree node value. | SafeKey | - | +| disabled | 禁用树节点。 | boolean | false | +| isLeaf | 标记节点为叶子节点。 | boolean | false | +| key | 唯一树节点 key。 | React.Key | - | +| title | 树节点标题。 | ReactNode | - | +| value | 树节点值。 | SafeKey | - | ## 说明 -For large trees, avoid expanding all nodes by default. Prefer virtual scrolling, -keep the number of simultaneous TreeSelect instances low, and use -`treeCheckStrictly` when checkable mode has many nodes. +对于大型树,避免默认展开所有节点。优先使用虚拟滚动,减少同时存在的 TreeSelect 实例数量,并在可勾选节点较多时使用 `treeCheckStrictly`。 -In `treeCheckable` mode, removing a selected item from the selector and -unchecking the matching tree node produce the same selected values, but they are -different interactions. Both trigger `onChange`, and the `extra` argument may +在 `treeCheckable` 模式下,从选择器中移除选中项和取消勾选对应树节点会得到相同的选中值,但它们是不同的交互。二者都会触发 `onChange`,`extra` 参数可能 therefore differ. ## 本地开发 @@ -177,8 +169,8 @@ npm run compile npm run prepublishOnly ``` -The release flow is handled by `@rc-component/np` through the `rc-np` command after the package build. +包构建完成后,发布流程由 `@rc-component/np` 通过 `rc-np` 命令处理。 ## 许可证 -@rc-component/tree-select is released under the [MIT](./LICENSE.md) license. +@rc-component/tree-select 基于 [MIT](./LICENSE.md) 许可证发布。 From 100820e4f110f8a055162f9dfa893986e4cc8d88 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 01:28:45 +0800 Subject: [PATCH 13/25] chore: standardize rc tooling and docs --- .dumirc.ts | 8 ++++-- .github/workflows/surge-preview.yml | 2 +- README.md | 5 ++-- README.zh-CN.md | 4 ++- package.json | 38 ++++++++++++++--------------- tsconfig.json | 23 +++++++++++++---- vercel.json | 2 +- 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/.dumirc.ts b/.dumirc.ts index f140eae2..a563040c 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -1,14 +1,18 @@ import { defineConfig } from 'dumi'; +const basePath = process.env.GH_PAGES ? '/tree-select/' : '/'; +const publicPath = basePath; + export default defineConfig({ + outputPath: 'docs-dist', favicons: ['https://avatars0.githubusercontent.com/u/9441414?s=200&v=4'], themeConfig: { name: 'tree-select', logo: 'https://avatars0.githubusercontent.com/u/9441414?s=200&v=4', }, exportStatic: {}, - base: '/', - publicPath: '/', + base: basePath, + publicPath, styles: [ ` .markdown table { diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index 30f70a85..633f829c 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -27,7 +27,7 @@ jobs: with: surge_token: ${{ env.SURGE_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} - dist: dist + dist: docs-dist failOnError: false setCommitStatus: false - name: Skip Surge preview diff --git a/README.md b/README.md index 1e57bd2f..130312e0 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,14 @@ export default () => locally, or visit the online example: -. +Then open `http://localhost:8000`. ## API diff --git a/README.zh-CN.md b/README.zh-CN.md index 219ff8f4..c98af13e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -55,12 +55,14 @@ export default () => ,或访问在线示例:。 +然后打开 `http://localhost:8000`。 ## API diff --git a/package.json b/package.json index 2c39dbd9..dfa8272b 100644 --- a/package.json +++ b/package.json @@ -52,32 +52,32 @@ "@rc-component/dialog": "^1.2.0", "@rc-component/father-plugin": "^2.2.0", "@rc-component/form": "^1.4.0", - "@rc-component/np": "^1.0.3", + "@rc-component/np": "^1.0.4", "@rc-component/trigger": "^3.0.0", "@rc-component/virtual-list": "^1.0.1", - "@testing-library/react": "^16.0.0", - "@types/jest": "^29.5.13", - "@types/node": "^22.7.5", - "@types/react": "^18.3.11", - "@types/react-dom": "^18.0.0", - "@types/warning": "^3.0.3", + "@testing-library/react": "^15.0.7", + "@types/jest": "^29.5.14", + "@types/node": "^26.0.1", + "@types/react": "^18.3.31", + "@types/react-dom": "^18.3.7", + "@types/warning": "^3.0.4", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "@umijs/fabric": "^4.0.1", - "cross-env": "^7.0.3", - "dumi": "^2.4.12", + "cross-env": "^10.1.0", + "dumi": "^2.4.35", "eslint": "^8.57.1", "eslint-plugin-jest": "^27.9.0", - "eslint-plugin-unicorn": "^56.0.0", - "father": "^4.5.0", - "glob": "^11.0.0", - "husky": "^9.1.6", - "lint-staged": "^15.2.10", - "prettier": "^3.3.3", - "rc-test": "^7.1.1", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "typescript": "^5.6.3" + "eslint-plugin-unicorn": "^56.0.1", + "father": "^4.6.23", + "glob": "^13.0.6", + "husky": "^9.1.7", + "lint-staged": "^16.4.0", + "prettier": "^3.9.0", + "rc-test": "^7.1.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "typescript": "^5.9.3" }, "peerDependencies": { "react": "*", diff --git a/tsconfig.json b/tsconfig.json index b233ccba..3d5da56b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,10 +8,23 @@ "skipLibCheck": true, "esModuleInterop": true, "paths": { - "@/*": ["src/*"], - "@@/*": [".dumi/tmp/*"], - "@rc-component/tree-select": ["src/index.tsx"] - } + "@/*": [ + "src/*" + ], + "@@/*": [ + ".dumi/tmp/*" + ], + "@rc-component/tree-select": [ + "src/index.tsx" + ] + }, + "ignoreDeprecations": "5.0" }, - "include": [".dumirc.ts", ".fatherrc.ts", "src", "tests", "examples"] + "include": [ + ".dumirc.ts", + ".fatherrc.ts", + "src", + "tests", + "examples" + ] } diff --git a/vercel.json b/vercel.json index e884e1b3..5f9139ef 100644 --- a/vercel.json +++ b/vercel.json @@ -2,5 +2,5 @@ "framework": "umijs", "installCommand": "npm install", "buildCommand": "npm run build", - "outputDirectory": "dist" + "outputDirectory": "docs-dist" } From daa943ddbb87e320a1d47d1720cae831f267d0f4 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 02:01:09 +0800 Subject: [PATCH 14/25] chore: address standardization review comments --- .github/workflows/surge-preview.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index 633f829c..50782cc0 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -15,13 +15,23 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: persist-credentials: false + - name: Check Surge token + id: surge-token + env: + SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} + run: | + if [ -n "$SURGE_TOKEN" ]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + fi - name: Build preview - if: ${{ secrets.SURGE_TOKEN != '' }} + if: ${{ steps.surge-token.outputs.enabled == 'true' }} run: | npm install npm run build - uses: afc163/surge-preview@bf90a5a86111f6311ca42f0a5a0f80fb0fb03cec - if: ${{ secrets.SURGE_TOKEN != '' }} + if: ${{ steps.surge-token.outputs.enabled == 'true' }} env: SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} with: @@ -31,5 +41,5 @@ jobs: failOnError: false setCommitStatus: false - name: Skip Surge preview - if: ${{ secrets.SURGE_TOKEN == '' }} + if: ${{ steps.surge-token.outputs.enabled != 'true' }} run: echo "SURGE_TOKEN is not configured; skip Surge preview." From f99567c06cfd4fde34ca36160a6ec248a5fb4db9 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 12:24:49 +0800 Subject: [PATCH 15/25] ci: update GitHub Actions versions --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1375e7a4..fa4bc090 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,15 +29,15 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + uses: github/codeql-action/init@a0853c24544627f65ddf259abe73b1d18a591444 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + uses: github/codeql-action/autobuild@a0853c24544627f65ddf259abe73b1d18a591444 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e + uses: github/codeql-action/analyze@a0853c24544627f65ddf259abe73b1d18a591444 with: category: '/language:${{ matrix.language }}' From 4b4e8d5757a9f9f0f80731c9bccd316b94025ba9 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 12:30:25 +0800 Subject: [PATCH 16/25] ci: use resolvable CodeQL action ref --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fa4bc090..1375e7a4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,15 +29,15 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@a0853c24544627f65ddf259abe73b1d18a591444 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@a0853c24544627f65ddf259abe73b1d18a591444 + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@a0853c24544627f65ddf259abe73b1d18a591444 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e with: category: '/language:${{ matrix.language }}' From 249c87120210140a3b104cff1c3a878021378c10 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 13:14:23 +0800 Subject: [PATCH 17/25] chore: ignore dumi build output --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e0ae8dea..0a84a316 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ es .dumi/tmp .dumi/tmp-test .dumi/tmp-production +docs-dist .env.local -bun.lockb \ No newline at end of file +bun.lockb From 79ae2622a8a51c41f67203c14059463cc988cf76 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 13:28:20 +0800 Subject: [PATCH 18/25] docs: add license file --- LICENSE | 21 +++++++++++++++++++++ README.md | 2 +- README.zh-CN.md | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..bd0a1f72 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present react-component + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 130312e0..3b8e8f80 100644 --- a/README.md +++ b/README.md @@ -181,4 +181,4 @@ The release flow is handled by `@rc-component/np` through the `rc-np` command af ## License -@rc-component/tree-select is released under the [MIT](./LICENSE.md) license. +@rc-component/tree-select is released under the [MIT](./LICENSE) license. diff --git a/README.zh-CN.md b/README.zh-CN.md index c98af13e..f5b2fc6c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -175,4 +175,4 @@ npm run prepublishOnly ## 许可证 -@rc-component/tree-select 基于 [MIT](./LICENSE.md) 许可证发布。 +@rc-component/tree-select 基于 [MIT](./LICENSE) 许可证发布。 From a5baaabe527faba66c79e35a08050f0e8cba6195 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 14:02:43 +0800 Subject: [PATCH 19/25] ci: use actions checkout v7 --- .github/workflows/codeql.yml | 2 +- .github/workflows/react-doctor.yml | 2 +- .github/workflows/surge-preview.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1375e7a4..34678138 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/react-doctor.yml b/.github/workflows/react-doctor.yml index 07884617..29d6f76b 100644 --- a/.github/workflows/react-doctor.yml +++ b/.github/workflows/react-doctor.yml @@ -15,7 +15,7 @@ jobs: react-doctor: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + - uses: actions/checkout@v7 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index 50782cc0..ef5a81d8 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -12,7 +12,7 @@ jobs: preview: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + - uses: actions/checkout@v7 with: persist-credentials: false - name: Check Surge token From a732f0fa1c033bd2fe926886da201d94fc0b07c5 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 14:32:33 +0800 Subject: [PATCH 20/25] chore: standardize package metadata --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index dfa8272b..a000e94c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "react-tree-select", "tree-select" ], - "homepage": "https://github.com/react-component/tree-select", + "homepage": "https://react-component.github.io/tree-select", "bugs": { "url": "https://github.com/react-component/tree-select/issues" }, @@ -82,5 +82,8 @@ "peerDependencies": { "react": "*", "react-dom": "*" + }, + "publishConfig": { + "access": "public" } } From 31f633b7c75b4eea14b676c47594782fadd3fbc6 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 14:38:51 +0800 Subject: [PATCH 21/25] ci: standardize dependabot updates --- .github/dependabot.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d0a9746f..3b730ef9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,19 @@ version: 2 updates: -- package-ecosystem: npm - directory: "/" - schedule: - interval: daily + - package-ecosystem: npm + directory: '/' + schedule: + interval: weekly + day: monday + time: '21:00' + timezone: Asia/Shanghai + open-pull-requests-limit: 10 + + - package-ecosystem: github-actions + directory: '/' + schedule: + interval: weekly + day: monday + time: '21:00' + timezone: Asia/Shanghai + open-pull-requests-limit: 10 From 55c801b7cf9ff5100713f787954aea1f4bc0927b Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 17:16:55 +0800 Subject: [PATCH 22/25] chore: refine preview workflow ignores --- .github/workflows/surge-preview.yml | 3 +++ .prettierignore | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 .prettierignore diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml index ef5a81d8..394f2b02 100644 --- a/.github/workflows/surge-preview.yml +++ b/.github/workflows/surge-preview.yml @@ -11,6 +11,9 @@ permissions: jobs: preview: runs-on: ubuntu-latest + concurrency: + group: surge-preview-${{ github.event.pull_request.number }} + cancel-in-progress: true steps: - uses: actions/checkout@v7 with: diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..c466d872 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +node_modules +coverage +docs-dist +dist +es +lib +.dumi/tmp +.dumi/tmp-production +.vercel +package-lock.json +pnpm-lock.yaml +yarn.lock +bun.lockb +*.log From fa0413af99ba9217c5d92c5a25104672d4c9448e Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 17:37:10 +0800 Subject: [PATCH 23/25] docs: polish Chinese README wording --- README.zh-CN.md | 143 ++++++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index f5b2fc6c..46fdf21c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -15,16 +15,15 @@

English | 简体中文

- ## 特性 -| 范围 | 支持 | -| --------- | --------------------------------------------------------- | -| 数据 | 树数据、简单模式和自定义字段名 | +| 范围 | 支持 | +| ---- | ---------------------------------- | +| 数据 | 树数据、简单模式和自定义字段名 | | 选择 | 单选、多选、勾选、严格勾选和标注值 | -| 搜索 | 受控搜索、自定义过滤和自动清除 | -| 加载 | 异步树加载和受控 loaded keys | -| 规模 | 支持可配置列表指标的虚拟滚动 | +| 搜索 | 受控搜索、自定义过滤和自动清除 | +| 加载 | 异步树加载和受控 loaded keys | +| 规模 | 支持可配置列表指标的虚拟滚动 | ## 安装 @@ -70,83 +69,83 @@ npm start TreeSelect 还接受来自 `@rc-component/select` `BaseSelect` 的公共属性,但内部使用的 `mode`、`classNames`、`styles` 和由 TreeSelect 重新定义的 `showSearch` 除外。 -| 名称 | 说明 | 类型 | 默认值 | -| ----------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | -| autoClearSearchValue | 已弃用。请改用 `showSearch.autoClearSearchValue`。 | boolean | true | -| classNames | 语义className。 | `Partial> & { popup?: Partial> }` | - | -| defaultValue | 初始选中值。 | `ValueType` | - | -| fieldNames | 自定义树数据的字段名称。 | `FieldNames` | - | -| filterTreeNode | 已弃用。请改用 `showSearch.filterTreeNode`。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | -| inputValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | -| labelInValue | 是否返回标记值对象而不是原始值。 | boolean | false | -| listHeight | 弹层列表高度。 | number | 200 | -| listItemHeight | 弹层列表项的高度。 | number | 20 | -| listItemScrollOffset | 弹层列表项滚动偏移。 | number | 0 | -| loadData | 异步加载树数据。 | `(dataNode: LegacyDataNode) => Promise` | - | -| maxCount | 多重或可检查模式下的最大选定项目数。 | number | - | -| multiple | 启用多项选择。 | boolean | false | -| onChange | 当选定值更改时调用。 | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | -| onDeselect | 当取消选择某个值时调用。 | `(value: ValueType, option: OptionType) => void` | - | -| onPopupVisibleChange | 当弹层窗口可见性发生变化时调用。 | `(open: boolean) => void` | - | -| onSearch | 已弃用。请改用 `showSearch.onSearch`。 | `(value: string) => void` | - | -| onSelect | 选择值时调用。 | `(value: ValueType, option: OptionType) => void` | - | -| onTreeExpand | 当扩展树键更改时调用。 | `(expandedKeys: SafeKey[]) => void` | - | -| onTreeLoad | 当异步加载的键发生变化时调用。 | `(loadedKeys: SafeKey[]) => void` | - | -| searchValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | -| showCheckedStrategy | 配置检查值的显示方式。 | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | 当 `treeCheckable` 使能时为 `SHOW_CHILD`,否则为 `SHOW_ALL` | -| showSearch | 启用搜索或配置搜索行为。 | boolean \| `SearchConfig` | - | -| showTreeIcon | 是否显示树形图标。 | boolean | false | -| styles | 语义化样式。 | `Partial> & { popup?: Partial> }` | - | -| switcherIcon | 自定义树切换器图标。 | `IconType` | - | -| treeCheckable | 是否在树中显示复选框。 | boolean \| ReactNode | false | -| treeCheckStrictly | 精确检查树节点,无需父子关联。 | boolean | false | -| treeData | 树节点数据。 | `OptionType[]` | - | -| treeDataSimpleMode | 启用简单树数据模式。 | boolean \| `SimpleModeConfig` | false | -| treeDefaultExpandAll | 默认展开所有树节点。 | boolean | false | -| treeDefaultExpandedKeys | 初始扩展树键。 | `SafeKey[]` | - | -| treeExpandAction | 树节点展开触发行为。 | false \| `click` \| `doubleClick` | `click` | -| treeExpandedKeys | 受控的扩展树键。 | `SafeKey[]` | - | -| treeIcon | 自定义树图标。 | `IconType` | - | -| treeLine | 是否显示树线。 | boolean | false | -| treeLoadedKeys | 受控加载的树键。 | `SafeKey[]` | - | -| treeMotion | 树运动配置。 | any | - | -| treeNodeFilterProp | 已弃用。请改用 `showSearch.treeNodeFilterProp`。 | string | `value` | -| treeNodeLabelProp | 作为选中标签渲染的树节点属性。 | string | `title` | -| treeTitleRender | 自定义树节点标题渲染器。 | `(node: OptionType) => ReactNode` | - | -| value | 受控选中值。 | `ValueType` | - | -| virtual | 设置为 `false` 时禁用虚拟滚动。 | boolean | - | +| 名称 | 说明 | 类型 | 默认值 | +| ----------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| autoClearSearchValue | 已弃用。请改用 `showSearch.autoClearSearchValue`。 | boolean | true | +| classNames | 语义 className。 | `Partial> & { popup?: Partial> }` | - | +| defaultValue | 初始选中值。 | `ValueType` | - | +| fieldNames | 自定义树数据的字段名称。 | `FieldNames` | - | +| filterTreeNode | 已弃用。请改用 `showSearch.filterTreeNode`。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| inputValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | +| labelInValue | 是否返回标记值对象而不是原始值。 | boolean | false | +| listHeight | 弹层列表高度。 | number | 200 | +| listItemHeight | 弹层列表项的高度。 | number | 20 | +| listItemScrollOffset | 弹层列表项滚动偏移。 | number | 0 | +| loadData | 异步加载树数据。 | `(dataNode: LegacyDataNode) => Promise` | - | +| maxCount | 多重或可检查模式下的最大选定项目数。 | number | - | +| multiple | 启用多项选择。 | boolean | false | +| onChange | 当选定值更改时调用。 | `(value: ValueType, labelList: ReactNode[], extra: ChangeEventExtra) => void` | - | +| onDeselect | 当取消选择某个值时调用。 | `(value: ValueType, option: OptionType) => void` | - | +| onPopupVisibleChange | 当弹层窗口可见性发生变化时调用。 | `(open: boolean) => void` | - | +| onSearch | 已弃用。请改用 `showSearch.onSearch`。 | `(value: string) => void` | - | +| onSelect | 选择值时调用。 | `(value: ValueType, option: OptionType) => void` | - | +| onTreeExpand | 当扩展树键更改时调用。 | `(expandedKeys: SafeKey[]) => void` | - | +| onTreeLoad | 当异步加载的键发生变化时调用。 | `(loadedKeys: SafeKey[]) => void` | - | +| searchValue | 已弃用。请改用 `showSearch.searchValue`。 | string | - | +| showCheckedStrategy | 配置检查值的显示方式。 | `SHOW_ALL` \| `SHOW_PARENT` \| `SHOW_CHILD` | 当 `treeCheckable` 使能时为 `SHOW_CHILD`,否则为 `SHOW_ALL` | +| showSearch | 启用搜索或配置搜索行为。 | boolean \| `SearchConfig` | - | +| showTreeIcon | 是否显示树形图标。 | boolean | false | +| styles | 语义化样式。 | `Partial> & { popup?: Partial> }` | - | +| switcherIcon | 自定义树切换器图标。 | `IconType` | - | +| treeCheckable | 是否在树中显示复选框。 | boolean \| ReactNode | false | +| treeCheckStrictly | 精确检查树节点,无需父子关联。 | boolean | false | +| treeData | 树节点数据。 | `OptionType[]` | - | +| treeDataSimpleMode | 启用简单树数据模式。 | boolean \| `SimpleModeConfig` | false | +| treeDefaultExpandAll | 默认展开所有树节点。 | boolean | false | +| treeDefaultExpandedKeys | 初始扩展树键。 | `SafeKey[]` | - | +| treeExpandAction | 树节点展开触发行为。 | false \| `click` \| `doubleClick` | `click` | +| treeExpandedKeys | 受控的扩展树键。 | `SafeKey[]` | - | +| treeIcon | 自定义树图标。 | `IconType` | - | +| treeLine | 是否显示树线。 | boolean | false | +| treeLoadedKeys | 受控加载的树键。 | `SafeKey[]` | - | +| treeMotion | 树运动配置。 | any | - | +| treeNodeFilterProp | 已弃用。请改用 `showSearch.treeNodeFilterProp`。 | string | `value` | +| treeNodeLabelProp | 作为选中标签渲染的树节点属性。 | string | `title` | +| treeTitleRender | 自定义树节点标题渲染器。 | `(node: OptionType) => ReactNode` | - | +| value | 受控选中值。 | `ValueType` | - | +| virtual | 设置为 `false` 时禁用虚拟滚动。 | boolean | - | ### SearchConfig -| 名称 | 说明 | 类型 | 默认值 | -| -------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- | -| autoClearSearchValue | 在多种模式下选择或取消选择后清除搜索输入。 | boolean | true | -| filterTreeNode | 根据搜索输入过滤树节点。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | -| onSearch | 当搜索输入更改时调用。 | `(value: string) => void` | - | -| searchValue | 受控搜索输入值。 | string | - | +| 名称 | 说明 | 类型 | 默认值 | +| -------------------- | ---------------------------------------------- | ---------------------------------------------------------------- | ------- | +| autoClearSearchValue | 在多种模式下选择或取消选择后清除搜索输入。 | boolean | true | +| filterTreeNode | 根据搜索输入过滤树节点。 | boolean \| `(inputValue: string, treeNode: DataNode) => boolean` | - | +| onSearch | 当搜索输入更改时调用。 | `(value: string) => void` | - | +| searchValue | 受控搜索输入值。 | string | - | | treeNodeFilterProp | 启用 `filterTreeNode` 时用于过滤的树节点属性。 | string | `value` | ### DataNode -| 名称 | 说明 | 类型 | 默认值 | -| -------- | ---------------------- | ------------ | ------- | -| children | 子树节点。 | `DataNode[]` | - | -| disabled | 禁用树节点。 | boolean | false | -| key | 唯一树节点 key。 | `React.Key` | - | -| title | 树节点标题。 | ReactNode | - | -| value | 树节点值。 | `SafeKey` | - | +| 名称 | 说明 | 类型 | 默认值 | +| -------- | ---------------- | ------------ | ------ | +| children | 子树节点。 | `DataNode[]` | - | +| disabled | 禁用树节点。 | boolean | false | +| key | 唯一树节点 key。 | `React.Key` | - | +| title | 树节点标题。 | ReactNode | - | +| value | 树节点值。 | `SafeKey` | - | ### TreeNode 推荐使用 `treeData`。`TreeNode` 仅为兼容旧用法保留。 -| 名称 | 说明 | 类型 | 默认值 | -| -------- | ----------------------------- | --------- | ------- | -| disabled | 禁用树节点。 | boolean | false | -| isLeaf | 标记节点为叶子节点。 | boolean | false | -| key | 唯一树节点 key。 | React.Key | - | -| title | 树节点标题。 | ReactNode | - | -| value | 树节点值。 | SafeKey | - | +| 名称 | 说明 | 类型 | 默认值 | +| -------- | -------------------- | --------- | ------ | +| disabled | 禁用树节点。 | boolean | false | +| isLeaf | 标记节点为叶子节点。 | boolean | false | +| key | 唯一树节点 key。 | React.Key | - | +| title | 树节点标题。 | ReactNode | - | +| value | 树节点值。 | SafeKey | - | ## 说明 From e07fb5a2e980e64605bff1ca2d504639fc672849 Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 19:39:50 +0800 Subject: [PATCH 24/25] docs: document dumi dev server port --- README.md | 3 ++- README.zh-CN.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b8e8f80..36653f79 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@

English | 简体中文

- ## Highlights | Area | Support | @@ -171,6 +170,8 @@ npm run lint npm run compile ``` +The dumi site runs at `http://localhost:8000` by default. + ## Release ```bash diff --git a/README.zh-CN.md b/README.zh-CN.md index 46fdf21c..9f64d291 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -164,6 +164,8 @@ npm run lint npm run compile ``` +dumi 站点默认运行在 `http://localhost:8000`。 + ## 发布 ```bash From 7229a01e66ad853904d254061203f8ae317ec84d Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 28 Jun 2026 19:59:28 +0800 Subject: [PATCH 25/25] chore: standardize husky configuration --- .husky/pre-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index af5adff9..2312dc58 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -lint-staged \ No newline at end of file +npx lint-staged