From 384c7f339a3610044f8a68276c6a0458d7a60146 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 10:03:29 +0800
Subject: [PATCH 01/15] chore: standardize repository maintenance
---
.github/FUNDING.yml | 2 +
.github/dependabot.yml | 32 +++++++---
.github/workflows/codeql.yml | 22 ++++---
.github/workflows/react-doctor.yml | 22 +++++++
.github/workflows/surge-preview.yml | 48 +++++++++++++++
.github/workflows/test.yml | 16 +++++
README.md | 96 +++++++++++++++++------------
README.zh-CN.md | 77 +++++++++++++++++++++++
now.json | 11 ----
package.json | 8 +--
tsconfig.json | 5 +-
vercel.json | 6 ++
12 files changed, 272 insertions(+), 73 deletions(-)
create mode 100644 .github/FUNDING.yml
create mode 100644 .github/workflows/react-doctor.yml
create mode 100644 .github/workflows/surge-preview.yml
create mode 100644 .github/workflows/test.yml
create mode 100644 README.zh-CN.md
delete mode 100644 now.json
create mode 100644 vercel.json
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..758659a
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: ant-design
+open_collective: ant-design
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 5990d9c..5e6c7fa 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,11 +1,27 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
-
version: 2
updates:
- - package-ecosystem: "" # See documentation for possible values
- directory: "/" # Location of package manifests
+ - package-ecosystem: npm
+ directory: '/'
+ schedule:
+ interval: weekly
+ day: monday
+ time: '21:00'
+ timezone: Asia/Shanghai
+ open-pull-requests-limit: 10
+ groups:
+ npm-dependencies:
+ patterns:
+ - '*'
+
+ - package-ecosystem: github-actions
+ directory: '/'
schedule:
- interval: "weekly"
+ interval: weekly
+ day: monday
+ time: '21:00'
+ timezone: Asia/Shanghai
+ open-pull-requests-limit: 10
+ groups:
+ github-actions:
+ patterns:
+ - '*'
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 50d981e..6082fc6 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: "53 19 * * 0"
+ - cron: '36 13 * * 3'
jobs:
analyze:
@@ -20,22 +20,24 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: [ javascript ]
+ language: [javascript-typescript]
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v7
+ 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-doctor.yml b/.github/workflows/react-doctor.yml
new file mode 100644
index 0000000..29d6f76
--- /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@v7
+ 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 0000000..394f2b0
--- /dev/null
+++ b/.github/workflows/surge-preview.yml
@@ -0,0 +1,48 @@
+name: Surge Preview
+
+on:
+ pull_request:
+
+permissions:
+ contents: read
+ pull-requests: write
+ checks: write
+
+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:
+ 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: ${{ steps.surge-token.outputs.enabled == 'true' }}
+ run: |
+ npm install
+ npm run build
+ - uses: afc163/surge-preview@bf90a5a86111f6311ca42f0a5a0f80fb0fb03cec
+ if: ${{ steps.surge-token.outputs.enabled == 'true' }}
+ env:
+ SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
+ with:
+ surge_token: ${{ env.SURGE_TOKEN }}
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ dist: docs-dist
+ failOnError: false
+ setCommitStatus: false
+ - name: Skip Surge preview
+ if: ${{ steps.surge-token.outputs.enabled != 'true' }}
+ run: echo "SURGE_TOKEN is not configured; skip Surge preview."
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..10c0ebb
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,16 @@
+name: ✅ test
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+
+permissions:
+ contents: read
+
+jobs:
+ test:
+ uses: react-component/rc-test/.github/workflows/test-utoo.yml@main
+ secrets:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/README.md b/README.md
index 1354af2..d0092f1 100644
--- a/README.md
+++ b/README.md
@@ -1,57 +1,77 @@
-# @rc-component/overflow 🐾
-
-[![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/overflow.svg?style=flat-square
-[npm-url]: http://npmjs.org/package/@rc-component/overflow
-[github-actions-image]: https://github.com/react-component/overflow/workflows/CI/badge.svg
-[github-actions-url]: https://github.com/react-component/overflow/actions
-[codecov-image]: https://img.shields.io/codecov/c/github/react-component/overflow/master.svg?style=flat-square
-[codecov-url]: https://codecov.io/gh/react-component/overflow/branch/master
-[david-url]: https://david-dm.org/react-component/overflow
-[david-image]: https://david-dm.org/react-component/overflow/status.svg?style=flat-square
-[david-dev-url]: https://david-dm.org/react-component/overflow?type=dev
-[david-dev-image]: https://david-dm.org/react-component/overflow/dev-status.svg?style=flat-square
-[download-image]: https://img.shields.io/npm/dm/@rc-component/overflow.svg?style=flat-square
-[download-url]: https://npmjs.org/package/@rc-component/overflow
-[bundlephobia-url]: https://bundlephobia.com/result?p=@rc-component/overflow
-[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/@rc-component/overflow
-[dumi-url]: https://github.com/umijs/dumi
-[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
-
-Auto collapse box when overflow
-
-## Live Demo
-
-https://overflow-react-component.vercel.app/
+
+
@rc-component/overflow
+
Part of the Ant Design ecosystem.
+
📦 Auto-collapse React layout primitive for rendering visible items and overflow indicators.
+
+
+
+
+
+
+
+
+
+
+
+English | [简体中文](./README.zh-CN.md)
+
+## Highlights
+
+| Area | Support |
+| ------- | ----------------------------------------------------------------------------------------- |
+| Purpose | Auto-collapse React layout primitive for rendering visible items and overflow indicators. |
+| Package | `@rc-component/overflow` |
+| Release | `@rc-component/np` / `rc-np` |
## Install
-[](https://npmjs.org/package/@rc-component/overflow)
+```bash
+npm install @rc-component/overflow
+```
## Usage
-```ts
-// TODO
+```tsx | pure
+import Overflow from '@rc-component/overflow';
+
+export default () => (
+ {item}}
+ renderRest={items => +{items.length}}
+ />
+);
```
## API
-| Property | Type | Default | Description |
-| -------- | ---- | ------- | ----------- |
+| Prop | Description |
+| ------------ | -------------------------------- |
+| `data` | Items rendered by Overflow. |
+| `renderItem` | Render a visible item. |
+| `renderRest` | Render collapsed overflow items. |
## Development
-```
+```bash
npm install
npm start
+npm test
+npm run lint
+npm run tsc
+npm run compile
+```
+
+The dumi site runs at `http://localhost:8000`.
+
+## Release
+
+```bash
+npm run prepublishOnly
```
+The release flow is handled by `@rc-component/np` through the `rc-np` command when the package uses the shared release flow.
+
## License
-@rc-component/overflow is released under the MIT license.
+@rc-component/overflow is released under the [MIT](./LICENSE.md) license.
diff --git a/README.zh-CN.md b/README.zh-CN.md
new file mode 100644
index 0000000..1814137
--- /dev/null
+++ b/README.zh-CN.md
@@ -0,0 +1,77 @@
+
+
@rc-component/overflow
+
Ant Design 生态的一部分。
+
📦 用于自动折叠可见项与溢出项的 React 布局基础组件。
+
+
+
+
+
+
+
+
+
+
+
+简体中文 | [English](./README.md)
+
+## 亮点
+
+| 方向 | 支持 |
+| ---- | ------------------------------------------------- |
+| 定位 | 用于自动折叠可见项与溢出项的 React 布局基础组件。 |
+| 包名 | `@rc-component/overflow` |
+| 发布 | `@rc-component/np` / `rc-np` |
+
+## 安装
+
+```bash
+npm install @rc-component/overflow
+```
+
+## 用法
+
+```tsx | pure
+import Overflow from '@rc-component/overflow';
+
+export default () => (
+ {item}}
+ renderRest={items => +{items.length}}
+ />
+);
+```
+
+## API
+
+| 名称 | 说明 |
+| ------------ | ----------------------- |
+| `data` | Overflow 渲染的数据项。 |
+| `renderItem` | 渲染可见项。 |
+| `renderRest` | 渲染折叠后的溢出项。 |
+
+## 本地开发
+
+```bash
+npm install
+npm start
+npm test
+npm run lint
+npm run tsc
+npm run compile
+```
+
+本地 dumi 站点默认运行在 `http://localhost:8000`.
+
+## 发布
+
+```bash
+npm run prepublishOnly
+```
+
+发布流程通过 `@rc-component/np` 提供的 `rc-np` 命令处理。
+
+## 许可证
+
+@rc-component/overflow 基于 [MIT](./LICENSE.md) 协议发布。
diff --git a/now.json b/now.json
deleted file mode 100644
index 7b2f649..0000000
--- a/now.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "version": 2,
- "name": "rc-overflow",
- "builds": [
- {
- "src": "package.json",
- "use": "@vercel/static-build",
- "config": { "distDir": "docs-dist" }
- }
- ]
-}
\ No newline at end of file
diff --git a/package.json b/package.json
index 32bc953..696c21c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@rc-component/overflow",
"version": "1.0.1",
- "description": "Auto collapse box when overflow",
+ "description": "📦 Auto-collapse React layout primitive for rendering visible items and overflow indicators.",
"keywords": [
"react",
"react-component",
@@ -41,7 +41,8 @@
"prepublishOnly": "npm run compile && rc-np",
"lint": "eslint src/ --ext .tsx,.ts",
"lint:tsc": "tsc -p tsconfig.json --noEmit",
- "now-build": "npm run docs:build"
+ "build": "dumi build",
+ "tsc": "tsc -p tsconfig.json --noEmit"
},
"dependencies": {
"@babel/runtime": "^7.11.1",
@@ -68,9 +69,8 @@
"father": "^4.6.19",
"glob": "^10.0.0",
"less": "^3.10.3",
- "np": "^7.0.0",
"prettier": "^2.0.5",
- "rc-test": "^7.0",
+ "rc-test": "^7.1.3",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"regenerator-runtime": "^0.13.7",
diff --git a/tsconfig.json b/tsconfig.json
index 168ea06..006262f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -12,5 +12,6 @@
"@@/*": [".dumi/tmp/*"],
"rc-overflow": ["src/index.tsx"]
}
- }
-}
\ No newline at end of file
+ },
+ "include": ["**/*.ts", "**/*.tsx", ".dumirc.ts"]
+}
diff --git a/vercel.json b/vercel.json
new file mode 100644
index 0000000..5f9139e
--- /dev/null
+++ b/vercel.json
@@ -0,0 +1,6 @@
+{
+ "framework": "umijs",
+ "installCommand": "npm install",
+ "buildCommand": "npm run build",
+ "outputDirectory": "docs-dist"
+}
From 68c833fadfebaf4a5eebfc1780c06bb82ff2a8a4 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 11:59:38 +0800
Subject: [PATCH 02/15] chore: address review feedback
---
.github/workflows/surge-preview.yml | 2 +-
README.md | 4 ++--
README.zh-CN.md | 4 ++--
package.json | 2 +-
tsconfig.json | 3 ++-
vercel.json | 2 +-
6 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml
index 394f2b0..67305c5 100644
--- a/.github/workflows/surge-preview.yml
+++ b/.github/workflows/surge-preview.yml
@@ -31,7 +31,7 @@ jobs:
- name: Build preview
if: ${{ steps.surge-token.outputs.enabled == 'true' }}
run: |
- npm install
+ ut install
npm run build
- uses: afc163/surge-preview@bf90a5a86111f6311ca42f0a5a0f80fb0fb03cec
if: ${{ steps.surge-token.outputs.enabled == 'true' }}
diff --git a/README.md b/README.md
index d0092f1..33d42e5 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
-English | [简体中文](./README.zh-CN.md)
+English | 简体中文
## Highlights
@@ -54,7 +54,7 @@ export default () => (
## Development
```bash
-npm install
+ut install
npm start
npm test
npm run lint
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 1814137..10eff12 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -13,7 +13,7 @@
-简体中文 | [English](./README.md)
+简体中文 | English
## 亮点
@@ -54,7 +54,7 @@ export default () => (
## 本地开发
```bash
-npm install
+ut install
npm start
npm test
npm run lint
diff --git a/package.json b/package.json
index 696c21c..752eb6c 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"lint": "eslint src/ --ext .tsx,.ts",
"lint:tsc": "tsc -p tsconfig.json --noEmit",
"build": "dumi build",
- "tsc": "tsc -p tsconfig.json --noEmit"
+ "tsc": "npm run lint:tsc"
},
"dependencies": {
"@babel/runtime": "^7.11.1",
diff --git a/tsconfig.json b/tsconfig.json
index 006262f..5fb8dc4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,5 +13,6 @@
"rc-overflow": ["src/index.tsx"]
}
},
- "include": ["**/*.ts", "**/*.tsx", ".dumirc.ts"]
+ "include": ["**/*.ts", "**/*.tsx", ".dumirc.ts"],
+ "exclude": ["node_modules", "es", "lib", "dist", "docs-dist", ".doc", ".dumi/tmp", "coverage"]
}
diff --git a/vercel.json b/vercel.json
index 5f9139e..20b1714 100644
--- a/vercel.json
+++ b/vercel.json
@@ -1,6 +1,6 @@
{
"framework": "umijs",
- "installCommand": "npm install",
+ "installCommand": "ut install",
"buildCommand": "npm run build",
"outputDirectory": "docs-dist"
}
From 9c24bb55cee7e5a08e8be6c8fe1e9cc4da18ce35 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 12:04:10 +0800
Subject: [PATCH 03/15] chore: set up utoo for preview builds
---
.github/workflows/surge-preview.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.github/workflows/surge-preview.yml b/.github/workflows/surge-preview.yml
index 67305c5..ba9f1dd 100644
--- a/.github/workflows/surge-preview.yml
+++ b/.github/workflows/surge-preview.yml
@@ -28,6 +28,10 @@ jobs:
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
fi
+ - name: Setup utoo
+ if: ${{ steps.surge-token.outputs.enabled == 'true' }}
+ uses: utooland/setup-utoo@v1
+
- name: Build preview
if: ${{ steps.surge-token.outputs.enabled == 'true' }}
run: |
From 5516381411010a1e651ba360f48d111e1b2fbe0c Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 13:32:33 +0800
Subject: [PATCH 04/15] chore: use npm install for vercel preview
---
vercel.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vercel.json b/vercel.json
index 20b1714..5f9139e 100644
--- a/vercel.json
+++ b/vercel.json
@@ -1,6 +1,6 @@
{
"framework": "umijs",
- "installCommand": "ut install",
+ "installCommand": "npm install",
"buildCommand": "npm run build",
"outputDirectory": "docs-dist"
}
From 66dcafd3d6c796425b8030044b2c462801d29ff3 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 14:02:41 +0800
Subject: [PATCH 05/15] chore: align maintenance dependencies
---
package.json | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/package.json b/package.json
index 752eb6c..a62dd8e 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
"tsc": "npm run lint:tsc"
},
"dependencies": {
- "@babel/runtime": "^7.11.1",
+ "@babel/runtime": "^7.29.7",
"@rc-component/resize-observer": "^1.0.1",
"@rc-component/util": "^1.11.1",
"clsx": "^2.1.1"
@@ -53,32 +53,32 @@
"devDependencies": {
"@rc-component/father-plugin": "^2.2.0",
"@rc-component/np": "^1.0.4",
- "@testing-library/jest-dom": "^5.16.4",
- "@testing-library/react": "^16.3.0",
- "@types/jest": "^26.0.23",
- "@types/node": "^24.8.1",
- "@types/react": "^18.0.0",
- "@types/react-dom": "^18.0.0",
- "@typescript-eslint/eslint-plugin": "^5.59.0",
- "@typescript-eslint/parser": "^5.59.0",
- "@umijs/fabric": "^3.0.0",
- "dumi": "^2.0.0",
- "eslint": "^8.57.0",
- "eslint-plugin-jest": "^27.5.1",
- "eslint-plugin-unicorn": "^51.0.1",
- "father": "^4.6.19",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@types/jest": "^30.0.0",
+ "@types/node": "^26.0.1",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
+ "@typescript-eslint/eslint-plugin": "^8.62.1",
+ "@typescript-eslint/parser": "^8.62.1",
+ "@umijs/fabric": "^4.0.1",
+ "dumi": "^2.4.38",
+ "eslint": "^9.39.4",
+ "eslint-plugin-jest": "^29.15.4",
+ "eslint-plugin-unicorn": "^65.0.1",
+ "father": "^4.6.24",
"glob": "^10.0.0",
- "less": "^3.10.3",
- "prettier": "^2.0.5",
+ "less": "^4.6.7",
+ "prettier": "^3.9.4",
"rc-test": "^7.1.3",
- "react": "^18.0.0",
- "react-dom": "^18.0.0",
+ "react": "^19.2.7",
+ "react-dom": "^19.2.7",
"regenerator-runtime": "^0.13.7",
- "typescript": "~5.3.3"
+ "typescript": "^6.0.3"
},
"peerDependencies": {
- "react": ">=16.9.0",
- "react-dom": ">=16.9.0"
+ "react": "^19.2.7",
+ "react-dom": "^19.2.7"
},
"cnpm": {
"mode": "npm"
From 98612e6c3339f07e5b831ee209c2a73466d9d2bb Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 14:24:32 +0800
Subject: [PATCH 06/15] chore: fix upgraded test tooling
---
eslint.config.mjs | 64 ++++++++++++++++++++
package.json | 8 ++-
tests/__snapshots__/index.spec.tsx.snap | 2 +-
tests/__snapshots__/invalidate.spec.tsx.snap | 2 +-
tests/__snapshots__/raw.spec.tsx.snap | 2 +-
tests/__snapshots__/ssr.spec.tsx.snap | 2 +-
6 files changed, 75 insertions(+), 5 deletions(-)
create mode 100644 eslint.config.mjs
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..8291c83
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,64 @@
+import { FlatCompat } from '@eslint/eslintrc';
+import js from '@eslint/js';
+import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
+import { createRequire } from 'node:module';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const require = createRequire(import.meta.url);
+
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended,
+ allConfig: js.configs.all,
+});
+
+const supportedTsRules = new Set(
+ Object.keys(tsEslintPlugin.rules).map(ruleName => `@typescript-eslint/${ruleName}`),
+);
+
+function normalizeConfig(config) {
+ const next = { ...config };
+
+ if (next.rules) {
+ next.rules = Object.fromEntries(
+ Object.entries(next.rules).filter(([ruleName]) => {
+ if (ruleName.startsWith('@babel/')) {
+ return false;
+ }
+ return !ruleName.startsWith('@typescript-eslint/') || supportedTsRules.has(ruleName);
+ }),
+ );
+ }
+
+ return next;
+}
+
+export default [
+ {
+ ignores: [
+ 'node_modules/',
+ 'coverage/',
+ 'es/',
+ 'lib/',
+ 'dist/',
+ 'docs-dist/',
+ '.dumi/',
+ '.doc/',
+ '.vercel/',
+ '.eslintrc.js',
+ ],
+ },
+ ...compat.config(require('./.eslintrc.js')).map(normalizeConfig),
+ {
+ rules: {
+ '@typescript-eslint/no-empty-object-type': 'off',
+ '@typescript-eslint/no-unsafe-function-type': 'off',
+ '@typescript-eslint/no-unused-vars': 'off',
+ '@typescript-eslint/no-useless-constructor': 'off',
+ '@typescript-eslint/consistent-indexed-object-style': 'off',
+ },
+ },
+];
diff --git a/package.json b/package.json
index a62dd8e..c8ec775 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,13 @@
"react": "^19.2.7",
"react-dom": "^19.2.7",
"regenerator-runtime": "^0.13.7",
- "typescript": "^6.0.3"
+ "typescript": "^6.0.3",
+ "@eslint/eslintrc": "^3.3.5",
+ "@eslint/js": "^9.39.4",
+ "eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-jsx-a11y": "^6.10.2",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^7.1.1"
},
"peerDependencies": {
"react": "^19.2.7",
diff --git a/tests/__snapshots__/index.spec.tsx.snap b/tests/__snapshots__/index.spec.tsx.snap
index aab408a..527d658 100644
--- a/tests/__snapshots__/index.spec.tsx.snap
+++ b/tests/__snapshots__/index.spec.tsx.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Overflow.Basic customize component 1`] = `
Date: Wed, 1 Jul 2026 14:26:44 +0800
Subject: [PATCH 07/15] docs: align Chinese README language switch
---
README.zh-CN.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 10eff12..f1cea4c 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -13,7 +13,7 @@
-简体中文 | English
+English | 简体中文
## 亮点
From 631d7168de6e5144946f1f4ae231ae7e97fa78d5 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 14:34:49 +0800
Subject: [PATCH 08/15] fix: preserve React peer dependency range
---
package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index c8ec775..ac524f1 100644
--- a/package.json
+++ b/package.json
@@ -83,8 +83,8 @@
"eslint-plugin-react-hooks": "^7.1.1"
},
"peerDependencies": {
- "react": "^19.2.7",
- "react-dom": "^19.2.7"
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
},
"cnpm": {
"mode": "npm"
From 6f2b389d6446c9f4d242c402d031ef2dd5ad47b6 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 14:45:46 +0800
Subject: [PATCH 09/15] chore: fix upgraded tooling checks
---
examples/fill-width.tsx | 4 ++--
src/RawItem.tsx | 2 +-
tsconfig.json | 4 ++++
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/examples/fill-width.tsx b/examples/fill-width.tsx
index 3f2db62..ae6dee6 100644
--- a/examples/fill-width.tsx
+++ b/examples/fill-width.tsx
@@ -61,8 +61,8 @@ const Demo = () => {
const [inputValue, setInputValue] = React.useState('');
const [inputWidth, setInputWidth] = React.useState(0);
const [data, setData] = React.useState(createData(3));
- const inputRef = React.useRef();
- const measureRef = React.useRef();
+ const inputRef = React.useRef(null);
+ const measureRef = React.useRef(null);
useLayoutEffect(() => {
setInputWidth(measureRef.current.offsetWidth);
diff --git a/src/RawItem.tsx b/src/RawItem.tsx
index 166f032..4c09c17 100644
--- a/src/RawItem.tsx
+++ b/src/RawItem.tsx
@@ -7,7 +7,7 @@ export type ComponentType =
| React.ComponentType
| React.ForwardRefExoticComponent
| React.FC
- | keyof React.ReactHTML;
+ | keyof HTMLElementTagNameMap;
export interface RawItemProps extends React.HTMLAttributes {
component?: ComponentType;
diff --git a/tsconfig.json b/tsconfig.json
index 5fb8dc4..84c643d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,10 @@
{
"compilerOptions": {
"target": "esnext",
+ "ignoreDeprecations": "6.0",
+ "strict": false,
+ "noUncheckedSideEffectImports": false,
+ "types": ["node", "jest"],
"moduleResolution": "node",
"baseUrl": "./",
"jsx": "react",
From a713ef903af7123514d7e96384343ed9c31bb266 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 14:56:21 +0800
Subject: [PATCH 10/15] chore: align TypeScript 6 tooling checks
---
global.d.ts | 1 +
tsconfig.json | 11 ++++-------
2 files changed, 5 insertions(+), 7 deletions(-)
create mode 100644 global.d.ts
diff --git a/global.d.ts b/global.d.ts
new file mode 100644
index 0000000..1ea3960
--- /dev/null
+++ b/global.d.ts
@@ -0,0 +1 @@
+declare module '*.less';
diff --git a/tsconfig.json b/tsconfig.json
index 84c643d..9267fb1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,20 +1,17 @@
{
"compilerOptions": {
"target": "esnext",
- "ignoreDeprecations": "6.0",
"strict": false,
- "noUncheckedSideEffectImports": false,
"types": ["node", "jest"],
- "moduleResolution": "node",
- "baseUrl": "./",
+ "moduleResolution": "bundler",
"jsx": "react",
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
- "@/*": ["src/*"],
- "@@/*": [".dumi/tmp/*"],
- "rc-overflow": ["src/index.tsx"]
+ "@/*": ["./src/*"],
+ "@@/*": ["./.dumi/tmp/*"],
+ "rc-overflow": ["./src/index.tsx"]
}
},
"include": ["**/*.ts", "**/*.tsx", ".dumirc.ts"],
From 3893644206d60335996fc386956019fbe4466600 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 15:24:46 +0800
Subject: [PATCH 11/15] test: fix mount helper type
---
tests/wrapper.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/wrapper.ts b/tests/wrapper.ts
index 1f99d6f..5727932 100644
--- a/tests/wrapper.ts
+++ b/tests/wrapper.ts
@@ -124,7 +124,7 @@ class NodeCollection {
}
}
-export function mount(element: React.ReactElement) {
+export function mount(element: React.ReactElement): any {
let mergedElement = element;
const result = render(mergedElement);
From de03923dbfe83663e469d4946789c5022f3829b9 Mon Sep 17 00:00:00 2001
From: afc163
Date: Wed, 1 Jul 2026 18:36:40 +0800
Subject: [PATCH 12/15] docs: use npm install in README
---
README.md | 2 +-
README.zh-CN.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 33d42e5..9849680 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ export default () => (
## Development
```bash
-ut install
+npm install
npm start
npm test
npm run lint
diff --git a/README.zh-CN.md b/README.zh-CN.md
index f1cea4c..c684e4c 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -54,7 +54,7 @@ export default () => (
## 本地开发
```bash
-ut install
+npm install
npm start
npm test
npm run lint
From 68492fec0ce10c9453838ea2def43c4d0c26f9cd Mon Sep 17 00:00:00 2001
From: afc163
Date: Thu, 2 Jul 2026 11:54:03 +0800
Subject: [PATCH 13/15] chore: migrate to native eslint flat config
---
.eslintrc.js | 13 -----
eslint.config.mjs | 131 +++++++++++++++++++++++++++++++---------------
package.json | 18 +++----
3 files changed, 97 insertions(+), 65 deletions(-)
delete mode 100644 .eslintrc.js
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index cf8ad0b..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const base = require('@umijs/fabric/dist/eslint');
-
-module.exports = {
- ...base,
- rules: {
- ...base.rules,
- 'no-template-curly-in-string': 0,
- 'prefer-promise-reject-errors': 0,
- 'react/no-array-index-key': 0,
- 'react/sort-comp': 0,
- '@typescript-eslint/no-explicit-any': 0,
- },
-};
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 8291c83..d19be2a 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,42 +1,23 @@
-import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
-import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
-import { createRequire } from 'node:module';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
+import { defineConfig } from 'eslint/config';
+import prettier from 'eslint-config-prettier';
+import jest from 'eslint-plugin-jest';
+import react from 'eslint-plugin-react';
+import reactHooks from 'eslint-plugin-react-hooks';
+import globals from 'globals';
+import tseslint from 'typescript-eslint';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-const require = createRequire(import.meta.url);
-
-const compat = new FlatCompat({
- baseDirectory: __dirname,
- recommendedConfig: js.configs.recommended,
- allConfig: js.configs.all,
-});
-
-const supportedTsRules = new Set(
- Object.keys(tsEslintPlugin.rules).map(ruleName => `@typescript-eslint/${ruleName}`),
-);
-
-function normalizeConfig(config) {
- const next = { ...config };
-
- if (next.rules) {
- next.rules = Object.fromEntries(
- Object.entries(next.rules).filter(([ruleName]) => {
- if (ruleName.startsWith('@babel/')) {
- return false;
- }
- return !ruleName.startsWith('@typescript-eslint/') || supportedTsRules.has(ruleName);
- }),
- );
- }
-
- return next;
-}
-
-export default [
+export default defineConfig([
+ {
+ plugins: {
+ '@typescript-eslint': tseslint.plugin,
+ },
+ },
+ {
+ linterOptions: {
+ reportUnusedDisableDirectives: 'off',
+ },
+ },
{
ignores: [
'node_modules/',
@@ -48,17 +29,83 @@ export default [
'.dumi/',
'.doc/',
'.vercel/',
- '.eslintrc.js',
+ 'src/index.d.ts',
],
},
- ...compat.config(require('./.eslintrc.js')).map(normalizeConfig),
{
+ files: ['**/*.{js,jsx,ts,tsx}'],
+ extends: [
+ js.configs.recommended,
+ react.configs.flat.recommended,
+ react.configs.flat['jsx-runtime'],
+ prettier,
+ ],
+ plugins: {
+ 'react-hooks': reactHooks,
+ },
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node,
+ },
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ },
rules: {
+ 'no-async-promise-executor': 'off',
+ 'no-empty-pattern': 'off',
+ 'no-irregular-whitespace': 'off',
+ 'no-prototype-builtins': 'off',
+ 'no-useless-escape': 'off',
+ 'no-extra-boolean-cast': 'off',
+ 'no-undef': 'off',
+ 'no-unused-vars': 'off',
+ 'react/no-find-dom-node': 'off',
+ 'react/display-name': 'off',
+ 'react/no-unknown-property': 'off',
+ 'react/prop-types': 'off',
+ 'react-hooks/exhaustive-deps': 'warn',
+ 'react-hooks/rules-of-hooks': 'error',
+ },
+ },
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [...tseslint.configs.recommended],
+ rules: {
+ '@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unsafe-function-type': 'off',
+ '@typescript-eslint/no-unnecessary-type-constraint': 'off',
'@typescript-eslint/no-unused-vars': 'off',
- '@typescript-eslint/no-useless-constructor': 'off',
- '@typescript-eslint/consistent-indexed-object-style': 'off',
},
},
-];
+ {
+ files: ['src/**/*.{ts,tsx}'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+ },
+ {
+ files: ['tests/**/*.{js,jsx,ts,tsx}', '**/*.{test,spec}.{js,jsx,ts,tsx}'],
+ extends: [jest.configs['flat/recommended']],
+ rules: {
+ 'jest/no-disabled-tests': 'off',
+ 'jest/no-done-callback': 'off',
+ 'jest/no-identical-title': 'off',
+ 'jest/expect-expect': 'off',
+ 'jest/no-alias-methods': 'off',
+ 'jest/no-conditional-expect': 'off',
+ 'jest/no-export': 'off',
+ 'jest/no-standalone-expect': 'off',
+ 'jest/valid-expect': 'off',
+ 'jest/valid-title': 'off',
+ },
+ },
+]);
diff --git a/package.json b/package.json
index ac524f1..15b384a 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"clsx": "^2.1.1"
},
"devDependencies": {
+ "@eslint/js": "^9.39.4",
"@rc-component/father-plugin": "^2.2.0",
"@rc-component/np": "^1.0.4",
"@testing-library/jest-dom": "^6.9.1",
@@ -59,15 +60,17 @@
"@types/node": "^26.0.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
- "@typescript-eslint/eslint-plugin": "^8.62.1",
- "@typescript-eslint/parser": "^8.62.1",
- "@umijs/fabric": "^4.0.1",
"dumi": "^2.4.38",
"eslint": "^9.39.4",
+ "eslint-config-prettier": "^10.1.8",
+ "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^29.15.4",
- "eslint-plugin-unicorn": "^65.0.1",
+ "eslint-plugin-jsx-a11y": "^6.10.2",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^7.1.1",
"father": "^4.6.24",
"glob": "^10.0.0",
+ "globals": "^17.7.0",
"less": "^4.6.7",
"prettier": "^3.9.4",
"rc-test": "^7.1.3",
@@ -75,12 +78,7 @@
"react-dom": "^19.2.7",
"regenerator-runtime": "^0.13.7",
"typescript": "^6.0.3",
- "@eslint/eslintrc": "^3.3.5",
- "@eslint/js": "^9.39.4",
- "eslint-plugin-import": "^2.32.0",
- "eslint-plugin-jsx-a11y": "^6.10.2",
- "eslint-plugin-react": "^7.37.5",
- "eslint-plugin-react-hooks": "^7.1.1"
+ "typescript-eslint": "^8.62.1"
},
"peerDependencies": {
"react": ">=16.9.0",
From 2231518f43ff141e09226f8bd91e5eda23706e18 Mon Sep 17 00:00:00 2001
From: afc163
Date: Fri, 3 Jul 2026 10:58:09 +0800
Subject: [PATCH 14/15] chore: address review comments
---
eslint.config.mjs | 10 +++++++---
examples/fill-width.tsx | 6 ++++--
package.json | 2 --
tests/wrapper.ts | 21 +++++++++++++++++++--
4 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/eslint.config.mjs b/eslint.config.mjs
index d19be2a..40f08ec 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,5 +1,7 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
import prettier from 'eslint-config-prettier';
import jest from 'eslint-plugin-jest';
import react from 'eslint-plugin-react';
@@ -7,6 +9,8 @@ import reactHooks from 'eslint-plugin-react-hooks';
import globals from 'globals';
import tseslint from 'typescript-eslint';
+const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
+
export default defineConfig([
{
plugins: {
@@ -15,7 +19,7 @@ export default defineConfig([
},
{
linterOptions: {
- reportUnusedDisableDirectives: 'off',
+ reportUnusedDisableDirectives: 'warn',
},
},
{
@@ -26,10 +30,10 @@ export default defineConfig([
'lib/',
'dist/',
'docs-dist/',
+ '.docs-dist/',
'.dumi/',
'.doc/',
'.vercel/',
- 'src/index.d.ts',
],
},
{
@@ -88,7 +92,7 @@ export default defineConfig([
languageOptions: {
parserOptions: {
projectService: true,
- tsconfigRootDir: import.meta.dirname,
+ tsconfigRootDir,
},
},
},
diff --git a/examples/fill-width.tsx b/examples/fill-width.tsx
index ae6dee6..2a664b9 100644
--- a/examples/fill-width.tsx
+++ b/examples/fill-width.tsx
@@ -65,11 +65,13 @@ const Demo = () => {
const measureRef = React.useRef(null);
useLayoutEffect(() => {
- setInputWidth(measureRef.current.offsetWidth);
+ if (measureRef.current) {
+ setInputWidth(measureRef.current.offsetWidth);
+ }
}, [inputValue]);
React.useEffect(() => {
- inputRef.current.focus();
+ inputRef.current?.focus();
}, []);
return (
diff --git a/package.json b/package.json
index 15b384a..5dbd087 100644
--- a/package.json
+++ b/package.json
@@ -63,9 +63,7 @@
"dumi": "^2.4.38",
"eslint": "^9.39.4",
"eslint-config-prettier": "^10.1.8",
- "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^29.15.4",
- "eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"father": "^4.6.24",
diff --git a/tests/wrapper.ts b/tests/wrapper.ts
index 5727932..76a1f9d 100644
--- a/tests/wrapper.ts
+++ b/tests/wrapper.ts
@@ -124,7 +124,24 @@ class NodeCollection {
}
}
-export function mount(element: React.ReactElement): any {
+interface MountWrapper extends ReturnType {
+ find: (selector: string) => NodeCollection;
+ findItems: () => NodeCollection;
+ findRest: () => NodeCollection;
+ findPrefix: () => NodeCollection;
+ findSuffix: () => NodeCollection;
+ triggerResize: (clientWidth: number) => Promise;
+ triggerItemResize: (
+ index: number,
+ offsetWidth: number,
+ ) => Promise;
+ initSize: (width: number, itemWidth: number) => Promise;
+ setProps: (props: Record) => MountWrapper;
+ update: () => MountWrapper;
+ render: () => ChildNode | null;
+}
+
+export function mount(element: React.ReactElement): MountWrapper {
let mergedElement = element;
const result = render(mergedElement);
@@ -154,7 +171,7 @@ export function mount(element: React.ReactElement): any {
await flushResize();
};
- const wrapper = {
+ const wrapper: MountWrapper = {
...result,
find(selector: string) {
if (selector === 'ResizeObserver') {
From bef62a70715d39018e6617c1f678c71983ba6406 Mon Sep 17 00:00:00 2001
From: afc163
Date: Fri, 3 Jul 2026 11:34:19 +0800
Subject: [PATCH 15/15] ci: update legacy action versions
---
.github/workflows/main.yml | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index c99089b..a308097 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -11,14 +11,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
- uses: actions/checkout@master
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- - uses: actions/setup-node@v1
+ - uses: actions/setup-node@v6
with:
node-version: '18'
- name: cache package-lock.json
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: package-temp-dir
key: lock-${{ github.sha }}
@@ -35,7 +37,7 @@ jobs:
- name: cache node_modules
id: node_modules_cache_id
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@@ -48,16 +50,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
- uses: actions/checkout@master
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: restore cache from package-lock.json
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@@ -71,16 +75,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
- uses: actions/checkout@master
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: restore cache from package-lock.json
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
@@ -94,16 +100,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
- uses: actions/checkout@master
+ uses: actions/checkout@v7
+ with:
+ persist-credentials: false
- name: restore cache from package-lock.json
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: package-temp-dir
key: lock-${{ github.sha }}
- name: restore cache from node_modules
- uses: actions/cache@v3
+ uses: actions/cache@v5
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}