diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 6d81724..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const config = {
- extends: [require.resolve('@umijs/fabric/dist/eslint')],
- rules: {
- 'react/no-did-update-set-state': 0,
- 'react/no-find-dom-node': 0,
- 'import/no-extraneous-dependencies': 0,
- 'react/sort-comp': 0,
- },
-};
-
-module.exports = config;
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 3b730ef..5e6c7fa 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,6 +8,10 @@ updates:
time: '21:00'
timezone: Asia/Shanghai
open-pull-requests-limit: 10
+ groups:
+ npm-dependencies:
+ patterns:
+ - '*'
- package-ecosystem: github-actions
directory: '/'
@@ -17,3 +21,7 @@ updates:
time: '21:00'
timezone: Asia/Shanghai
open-pull-requests-limit: 10
+ groups:
+ github-actions:
+ patterns:
+ - '*'
diff --git a/README.md b/README.md
index 9dbe932..ee7912a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
@rc-component/tour
-
Part of the Ant Design ecosystem.
+
Part of the Ant Design ecosystem.
🧭 Guided React tours with masks, target tracking, keyboard navigation, and custom panels.
@@ -15,7 +15,6 @@
English | 简体中文
-
## Highlights
- Tracks step targets and renders guided panels through a trigger-backed popup.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 504f63c..9feeb18 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,6 +1,6 @@
@rc-component/tour
-
Ant Design 生态的一部分。
+
Ant Design 生态的一部分。
🧭 React 引导组件,用于创建分步产品导览。
@@ -15,7 +15,6 @@
English | 简体中文
-
## 特性
- 跟踪步骤目标并通过触发器支持的弹层窗口渲染引导面板。
@@ -69,53 +68,53 @@ npm start
### Tour
-| 名称 | 类型 | 默认值 | 说明 |
-| ----------------------- | ------------------------------------------------------------ | -------------- | ---------------------------------------------------- |
-| `animated` | boolean \| `{ placeholder: boolean }` | false | 启用目标占位动画。 |
-| `arrow` | boolean \| `{ pointAtCenter: boolean }` | true | 显示箭头,并可选择指向目标中心。 |
-| `builtinPlacements` | TriggerProps['builtinPlacements'] \| function | - | 自定义位置映射。 |
-| `className` | string | - | 面板 className。 |
-| `classNames` | `Partial
>` | - | 语义 className。 |
-| `closable` | boolean \| object | - | 关闭按钮配置。 |
-| `closeIcon` | React.ReactNode | - | 自定义关闭图标。 |
-| `current` | number | - | 受控当前步骤。 |
-| `defaultCurrent` | number | 0 | 初始当前步骤。 |
-| `defaultOpen` | boolean | - | 初始打开状态。 |
-| `disabledInteraction` | boolean | - | 禁用与目标区域的交互。 |
-| `gap` | Gap | - | 目标周围的间隙偏移和半径。 |
-| `getPopupContainer` | TriggerProps['getPopupContainer'] \| false | - | 弹层容器解析函数。使用 false 表示内联模式。 |
-| `keyboard` | boolean | true | 启用 Escape 和箭头键导航。 |
-| `mask` | boolean \| `{ style?: React.CSSProperties; color?: string }` | true | 遮罩配置。 |
-| `onChange` | `(current: number) => void` | - | 当前步骤更改时调用。 |
-| `onClose` | `(current: number) => void` | - | 引导关闭时调用。 |
-| `onFinish` | `() => void` | - | 引导完成后调用。 |
-| `onPopupAlign` | TriggerProps['onPopupAlign'] | - | 弹层对齐后调用。 |
-| `open` | boolean | - | 受控打开状态。 |
-| `placement` | PlacementType | - | 默认面板位置。 |
-| `prefixCls` | string | `'rc-tour'` | className 前缀。 |
-| `renderPanel` | `(props, current) => ReactNode` | - | 自定义面板渲染器。 |
-| `rootClassName` | string | - | 根 className。 |
-| `scrollIntoViewOptions` | boolean \| ScrollIntoViewOptions | 中心选项 | 目标滚动行为。 |
-| `steps` | TourStepInfo[] | [] | 漫游步骤。 |
-| `style` | React.CSSProperties | - | 面板风格。 |
-| `styles` | `Partial>` | - | 语义化样式。 |
-| `zIndex` | number | 1001 | 弹层 z 索引。 |
+| 名称 | 类型 | 默认值 | 说明 |
+| ----------------------- | ------------------------------------------------------------ | ----------- | ------------------------------------------- |
+| `animated` | boolean \| `{ placeholder: boolean }` | false | 启用目标占位动画。 |
+| `arrow` | boolean \| `{ pointAtCenter: boolean }` | true | 显示箭头,并可选择指向目标中心。 |
+| `builtinPlacements` | TriggerProps['builtinPlacements'] \| function | - | 自定义位置映射。 |
+| `className` | string | - | 面板 className。 |
+| `classNames` | `Partial>` | - | 语义 className。 |
+| `closable` | boolean \| object | - | 关闭按钮配置。 |
+| `closeIcon` | React.ReactNode | - | 自定义关闭图标。 |
+| `current` | number | - | 受控当前步骤。 |
+| `defaultCurrent` | number | 0 | 初始当前步骤。 |
+| `defaultOpen` | boolean | - | 初始打开状态。 |
+| `disabledInteraction` | boolean | - | 禁用与目标区域的交互。 |
+| `gap` | Gap | - | 目标周围的间隙偏移和半径。 |
+| `getPopupContainer` | TriggerProps['getPopupContainer'] \| false | - | 弹层容器解析函数。使用 false 表示内联模式。 |
+| `keyboard` | boolean | true | 启用 Escape 和箭头键导航。 |
+| `mask` | boolean \| `{ style?: React.CSSProperties; color?: string }` | true | 遮罩配置。 |
+| `onChange` | `(current: number) => void` | - | 当前步骤更改时调用。 |
+| `onClose` | `(current: number) => void` | - | 引导关闭时调用。 |
+| `onFinish` | `() => void` | - | 引导完成后调用。 |
+| `onPopupAlign` | TriggerProps['onPopupAlign'] | - | 弹层对齐后调用。 |
+| `open` | boolean | - | 受控打开状态。 |
+| `placement` | PlacementType | - | 默认面板位置。 |
+| `prefixCls` | string | `'rc-tour'` | className 前缀。 |
+| `renderPanel` | `(props, current) => ReactNode` | - | 自定义面板渲染器。 |
+| `rootClassName` | string | - | 根 className。 |
+| `scrollIntoViewOptions` | boolean \| ScrollIntoViewOptions | 中心选项 | 目标滚动行为。 |
+| `steps` | TourStepInfo[] | [] | 漫游步骤。 |
+| `style` | React.CSSProperties | - | 面板风格。 |
+| `styles` | `Partial>` | - | 语义化样式。 |
+| `zIndex` | number | 1001 | 弹层 z 索引。 |
### TourStepInfo
-| 名称 | 类型 | 默认值 | 说明 |
-| ----------------------- | ------------------------------------------ | --------- | --------------------------- |
-| `arrow` | boolean \| `{ pointAtCenter: boolean }` | inherited | 步骤箭头配置。 |
-| `className` | string | - | 步骤面板 className。 |
+| 名称 | 类型 | 默认值 | 说明 |
+| ----------------------- | ------------------------------------------ | --------- | -------------------- |
+| `arrow` | boolean \| `{ pointAtCenter: boolean }` | inherited | 步骤箭头配置。 |
+| `className` | string | - | 步骤面板 className。 |
| `closable` | boolean \| object | inherited | 步骤关闭按钮配置。 |
-| `closeIcon` | React.ReactNode | inherited | 步骤关闭图标。 |
-| `description` | React.ReactNode | - | 步骤描述。 |
-| `mask` | boolean \| object | inherited | 步骤遮罩配置。 |
-| `placement` | PlacementType | inherited | 步骤位置。 |
+| `closeIcon` | React.ReactNode | inherited | 步骤关闭图标。 |
+| `description` | React.ReactNode | - | 步骤描述。 |
+| `mask` | boolean \| object | inherited | 步骤遮罩配置。 |
+| `placement` | PlacementType | inherited | 步骤位置。 |
| `scrollIntoViewOptions` | boolean \| ScrollIntoViewOptions | inherited | 步骤滚动行为。 |
| `style` | React.CSSProperties | - | 步骤面板样式。 |
-| `target` | HTMLElement \| `() => HTMLElement \| null` | - | 目标元素或解析器。 |
-| `title` | React.ReactNode | - | 步骤标题。 |
+| `target` | HTMLElement \| `() => HTMLElement \| null` | - | 目标元素或解析器。 |
+| `title` | React.ReactNode | - | 步骤标题。 |
## 本地开发
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..40f08ec
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,115 @@
+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';
+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: {
+ '@typescript-eslint': tseslint.plugin,
+ },
+ },
+ {
+ linterOptions: {
+ reportUnusedDisableDirectives: 'warn',
+ },
+ },
+ {
+ ignores: [
+ 'node_modules/',
+ 'coverage/',
+ 'es/',
+ 'lib/',
+ 'dist/',
+ 'docs-dist/',
+ '.docs-dist/',
+ '.dumi/',
+ '.doc/',
+ '.vercel/',
+ ],
+ },
+ {
+ 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',
+ },
+ },
+ {
+ files: ['src/**/*.{ts,tsx}'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ tsconfigRootDir,
+ },
+ },
+ },
+ {
+ 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/global.d.ts b/global.d.ts
new file mode 100644
index 0000000..e0bd355
--- /dev/null
+++ b/global.d.ts
@@ -0,0 +1,11 @@
+///
+///
+///
+///
+///
+
+declare module '*.css';
+declare module '*.less';
+declare module 'jsonp';
+
+declare module 'moment/locale/zh-cn';
diff --git a/package.json b/package.json
index dafcb5d..7271ffe 100644
--- a/package.json
+++ b/package.json
@@ -47,29 +47,35 @@
"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/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
- "@testing-library/react": "^15.0.7",
- "@types/jest": "^29.5.14",
- "@types/minimatch": "^5.1.2",
+ "@testing-library/react": "^16.3.2",
+ "@types/jest": "^30.0.0",
"@types/node": "^26.0.1",
- "@types/react": "^18.3.31",
- "@types/react-dom": "^18.3.7",
- "@umijs/fabric": "^4.0.1",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
"cheerio": "1.0.0-rc.12",
- "dumi": "^2.4.35",
- "eslint": "^8.57.1",
- "father": "^4.6.23",
- "gh-pages": "^6.3.0",
- "prettier": "^3.9.0",
- "rc-test": "^7.1.3",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "typescript": "^5.9.3",
"cross-env": "^10.1.0",
+ "dumi": "^2.4.38",
+ "eslint": "^9.39.4",
+ "eslint-config-prettier": "^10.1.8",
+ "eslint-plugin-jest": "^29.15.4",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^7.1.1",
+ "father": "^4.6.24",
+ "gh-pages": "^6.3.0",
+ "globals": "^17.7.0",
"husky": "^9.1.7",
- "lint-staged": "^16.4.0"
+ "lint-staged": "^17.0.8",
+ "prettier": "^3.9.4",
+ "rc-test": "^7.1.3",
+ "react": "^19.2.7",
+ "react-dom": "^19.2.7",
+ "typescript": "^6.0.3",
+ "typescript-eslint": "^8.62.1"
},
"peerDependencies": {
"react": ">=16.9.0",
diff --git a/src/Tour.tsx b/src/Tour.tsx
index 8d2ef78..51169d7 100644
--- a/src/Tour.tsx
+++ b/src/Tour.tsx
@@ -65,7 +65,7 @@ const Tour: React.FC = props => {
...restProps
} = props;
- const triggerRef = React.useRef();
+ const triggerRef = React.useRef(null);
const [mergedCurrent, setMergedCurrent] = useControlledState(
defaultCurrent || 0,
diff --git a/tests/__snapshots__/index.test.tsx.snap b/tests/__snapshots__/index.test.tsx.snap
index c589d37..a51c698 100644
--- a/tests/__snapshots__/index.test.tsx.snap
+++ b/tests/__snapshots__/index.test.tsx.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Tour animated placeholder true 1`] = `
diff --git a/tsconfig.json b/tsconfig.json
index b2522b5..ae9f101 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,41 +1,28 @@
{
"compilerOptions": {
"target": "esnext",
- "moduleResolution": "node",
- "baseUrl": "./",
+ "moduleResolution": "bundler",
"jsx": "preserve",
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
- "@/*": [
- "src/*"
- ],
- "@@/*": [
- ".dumi/tmp/*"
- ],
- "@rc-component/tour": [
- "src/index.tsx"
- ],
- "@rc-component/tour/es": [
- "src"
- ],
- "@rc-component/tour/es/*": [
- "src/*"
- ]
+ "@/*": ["./src/*"],
+ "@@/*": ["./.dumi/tmp/*"],
+ "@rc-component/tour": ["./src/index.tsx"],
+ "@rc-component/tour/es": ["./src"],
+ "@rc-component/tour/es/*": ["./src/*"]
},
- "ignoreDeprecations": "5.0"
+ "strict": false,
+ "module": "ESNext"
},
"include": [
+ "global.d.ts",
".dumirc.ts",
".fatherrc.ts",
"src",
"tests",
"docs/examples"
],
- "exclude": [
- "docs-dist",
- "lib",
- "es"
- ]
+ "exclude": ["docs-dist", "lib", "es"]
}