Skip to content

Commit 4fcc5e1

Browse files
chenJJ-88claude
andcommitted
feat: add GitHub Pages deploy workflow, streamline CellRenderProps, fix CSS import type
- Add deploy.yml workflow for automatic GitHub Pages deployment on push to main - Simplify ci.yml: single Node 20, add docs:build step - Add base: '/react-cascading-input/' to rspress config for GitHub Pages routing - Remove redundant CellRenderProps fields: path, hasAdd, id - path: internal use only, consumers don't need it - hasAdd: already on ColumnConfig, redundant in render props - id: duplicate of node.id - Add css.d.ts type declaration to fix CSS import editor error - Enhance DemoSelect to demonstrate level/node/isLeaf usage - Auto-fix all biome lint/format issues Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 158ba1c commit 4fcc5e1

11 files changed

Lines changed: 287 additions & 103 deletions

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI
22

33
on:
44
push:
5-
branches: [main, master]
5+
branches: [main]
66
pull_request:
77

88
# 同一分支只保留最新一次运行,节省 CI 资源
@@ -12,22 +12,18 @@ concurrency:
1212

1313
jobs:
1414
verify:
15-
name: Lint & Test (Node ${{ matrix.node }})
15+
name: Lint, Test & Build
1616
runs-on: ubuntu-latest
17-
strategy:
18-
fail-fast: false
19-
matrix:
20-
node: [18, 20, 22]
2117
steps:
2218
- uses: actions/checkout@v4
2319

2420
- name: Setup pnpm
2521
uses: pnpm/action-setup@v4
2622

27-
- name: Setup Node.js ${{ matrix.node }}
23+
- name: Setup Node.js
2824
uses: actions/setup-node@v4
2925
with:
30-
node-version: ${{ matrix.node }}
26+
node-version: 20
3127
cache: pnpm
3228

3329
- name: Install dependencies
@@ -42,5 +38,8 @@ jobs:
4238
- name: Test
4339
run: pnpm test
4440

45-
- name: Build
41+
- name: Build library
4642
run: pnpm build
43+
44+
- name: Build docs
45+
run: pnpm docs:build

.github/workflows/deploy.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Deploy Docs
2+
3+
on:
4+
push:
5+
branches: [main]
6+
7+
# 同一分支只保留最新一次部署,避免并发冲突
8+
concurrency:
9+
group: deploy-docs-${{ github.ref }}
10+
cancel-in-progress: true
11+
12+
# 允许部署到 GitHub Pages
13+
permissions:
14+
contents: read
15+
pages: write
16+
id-token: write
17+
18+
jobs:
19+
build:
20+
name: Build Docs
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Setup pnpm
26+
uses: pnpm/action-setup@v4
27+
28+
- name: Setup Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: 20
32+
cache: pnpm
33+
34+
- name: Install dependencies
35+
run: pnpm install --frozen-lockfile
36+
37+
- name: Build docs
38+
run: pnpm docs:build
39+
40+
- name: Upload artifact
41+
uses: actions/upload-pages-artifact@v3
42+
with:
43+
path: doc_build
44+
45+
deploy:
46+
name: Deploy to GitHub Pages
47+
needs: build
48+
runs-on: ubuntu-latest
49+
environment:
50+
name: github-pages
51+
url: ${{ steps.deployment.outputs.page_url }}
52+
steps:
53+
- name: Deploy to GitHub Pages
54+
id: deployment
55+
uses: actions/deploy-pages@v4

rspress.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { defineConfig } from 'rspress/config';
33

44
export default defineConfig({
55
root: path.join(__dirname, 'docs'),
6+
// GitHub Pages 部署时以仓库名为 base 路径
7+
base: '/react-cascading-input/',
68
title: 'react-cascading-input',
79
description: '支持 Canvas 连线的级联树形输入 React 组件',
810
themeConfig: {
@@ -28,8 +30,6 @@ export default defineConfig({
2830
},
2931
],
3032
},
31-
socialLinks: [
32-
{ icon: 'github', mode: 'link', content: 'https://github.com/chenJJ-88/react-cascading-input' },
33-
],
33+
socialLinks: [{ icon: 'github', mode: 'link', content: 'https://github.com/chenJJ-88/react-cascading-input' }],
3434
},
3535
});

src/CascadingInput.tsx

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ const createChain = (columns: ColumnConfig[], level: number): TreeNode => {
1717
return node;
1818
};
1919

20-
export const CascadingInput: React.FC<CascadingInputProps> = ({
21-
value = [],
22-
onChange,
23-
columns,
24-
line = {},
25-
}) => {
20+
export const CascadingInput: React.FC<CascadingInputProps> = ({ value = [], onChange, columns, line = {} }) => {
2621
const lineStyle = line.style ?? 'curve';
2722
const lineColor = line.color ?? '#d9d9d9';
2823
const lineWidth = line.width ?? 1.5;
@@ -51,7 +46,9 @@ export const CascadingInput: React.FC<CascadingInputProps> = ({
5146
const currentId = path[0];
5247
return nodes.map((node) => {
5348
if (node.id === currentId) {
54-
if (path.length === 1) { return { ...node, [dataIndex]: val }; }
49+
if (path.length === 1) {
50+
return { ...node, [dataIndex]: val };
51+
}
5552
return { ...node, children: updateTreeValue(node.children || [], path.slice(1), val, dataIndex) };
5653
}
5754
return node;
@@ -79,7 +76,9 @@ export const CascadingInput: React.FC<CascadingInputProps> = ({
7976

8077
const deleteNodeCascade = (nodes: TreeNode[], path: string[]): TreeNode[] => {
8178
const targetId = path[0];
82-
if (path.length === 1) { return nodes.filter((n) => n.id !== targetId); }
79+
if (path.length === 1) {
80+
return nodes.filter((n) => n.id !== targetId);
81+
}
8382
return nodes
8483
.map((node) => {
8584
if (node.id === targetId) {
@@ -93,16 +92,17 @@ export const CascadingInput: React.FC<CascadingInputProps> = ({
9392
const handleValueChange = (path: string[], val: string, dataIndex: string) =>
9493
onChange?.(updateTreeValue(value, path, val, dataIndex));
9594

96-
const handleAdd = (path: string[], level: number) =>
97-
onChange?.(addSiblingNode(value, path, level));
95+
const handleAdd = (path: string[], level: number) => onChange?.(addSiblingNode(value, path, level));
9896

9997
const handleDelete = (path: string[]) => {
10098
const nextValue = deleteNodeCascade(value, path);
10199
onChange?.(nextValue.length === 0 ? [createChain(columns, 0)] : nextValue);
102100
};
103101

104102
const renderLevel = (nodes: TreeNode[], level: number, parentPath: string[] = []): React.ReactNode => {
105-
if (!columns[level]) { return null; }
103+
if (!columns[level]) {
104+
return null;
105+
}
106106
const col = columns[level];
107107
const isLeaf = level === columns.length - 1;
108108

@@ -127,38 +127,39 @@ export const CascadingInput: React.FC<CascadingInputProps> = ({
127127
})}
128128
{col.hasAdd && (
129129
<div className="tree-cell-action">
130-
{col.addRender
131-
? col.addRender({ onClick: () => handleAdd(currentPath, level) })
132-
: (
133-
<button
134-
type="button"
135-
className="tree-cell-action-btn"
136-
onClick={() => handleAdd(currentPath, level)}
137-
>
138-
添加
139-
</button>
140-
)}
130+
{col.addRender ? (
131+
col.addRender({ onClick: () => handleAdd(currentPath, level) })
132+
) : (
133+
<button
134+
type="button"
135+
className="tree-cell-action-btn"
136+
onClick={() => handleAdd(currentPath, level)}
137+
>
138+
添加
139+
</button>
140+
)}
141141
</div>
142142
)}
143143
</div>
144144

145-
{!isLeaf && node.children && node.children.length > 0 &&
145+
{!isLeaf &&
146+
node.children &&
147+
node.children.length > 0 &&
146148
renderLevel(node.children, level + 1, currentPath)}
147149

148-
{isLeaf && (
149-
col.deleteRender
150-
? col.deleteRender({ onClick: () => handleDelete(currentPath) })
151-
: (
152-
<button
153-
type="button"
154-
className="tree-delete-btn"
155-
onClick={() => handleDelete(currentPath)}
156-
title="删除整行"
157-
>
158-
删除
159-
</button>
160-
)
161-
)}
150+
{isLeaf &&
151+
(col.deleteRender ? (
152+
col.deleteRender({ onClick: () => handleDelete(currentPath) })
153+
) : (
154+
<button
155+
type="button"
156+
className="tree-delete-btn"
157+
onClick={() => handleDelete(currentPath)}
158+
title="删除整行"
159+
>
160+
删除
161+
</button>
162+
))}
162163
</div>
163164
);
164165
})}

src/demo/DemoCustomActions.tsx

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,31 +39,66 @@ const columns: ColumnConfig[] = [
3939
dataIndex: 'product',
4040
width: 120,
4141
hasAdd: true,
42-
addRender: ({ onClick }) => <button type="button" style={addBtnStyle} onClick={onClick}>+ 添加</button>,
43-
deleteRender: ({ onClick }) => <button type="button" style={deleteBtnStyle} onClick={onClick}>删除</button>,
42+
addRender: ({ onClick }) => (
43+
<button type="button" style={addBtnStyle} onClick={onClick}>
44+
+ 添加
45+
</button>
46+
),
47+
deleteRender: ({ onClick }) => (
48+
<button type="button" style={deleteBtnStyle} onClick={onClick}>
49+
删除
50+
</button>
51+
),
4452
render: ({ value, onChange, title }) => (
45-
<input style={inputStyle} placeholder={`请输入${title}`} value={value} onChange={(e) => onChange(e.target.value)} />
53+
<input
54+
style={inputStyle}
55+
placeholder={`请输入${title}`}
56+
value={value}
57+
onChange={(e) => onChange(e.target.value)}
58+
/>
4659
),
4760
},
4861
{
4962
title: '训练集群',
5063
dataIndex: 'region',
5164
width: 120,
5265
hasAdd: true,
53-
addRender: ({ onClick }) => <button type="button" style={addBtnStyle} onClick={onClick}>+ 添加</button>,
54-
deleteRender: ({ onClick }) => <button type="button" style={deleteBtnStyle} onClick={onClick}>删除</button>,
66+
addRender: ({ onClick }) => (
67+
<button type="button" style={addBtnStyle} onClick={onClick}>
68+
+ 添加
69+
</button>
70+
),
71+
deleteRender: ({ onClick }) => (
72+
<button type="button" style={deleteBtnStyle} onClick={onClick}>
73+
删除
74+
</button>
75+
),
5576
render: ({ value, onChange, title }) => (
56-
<input style={inputStyle} placeholder={`请输入${title}`} value={value} onChange={(e) => onChange(e.target.value)} />
77+
<input
78+
style={inputStyle}
79+
placeholder={`请输入${title}`}
80+
value={value}
81+
onChange={(e) => onChange(e.target.value)}
82+
/>
5783
),
5884
},
5985
{
6086
title: '框架版本',
6187
dataIndex: 'spec',
6288
width: 180,
6389
hasAdd: false,
64-
deleteRender: ({ onClick }) => <button type="button" style={deleteBtnStyle} onClick={onClick}>删除</button>,
90+
deleteRender: ({ onClick }) => (
91+
<button type="button" style={deleteBtnStyle} onClick={onClick}>
92+
删除
93+
</button>
94+
),
6595
render: ({ value, onChange, title }) => (
66-
<input style={inputStyle} placeholder={`请输入${title}`} value={value} onChange={(e) => onChange(e.target.value)} />
96+
<input
97+
style={inputStyle}
98+
placeholder={`请输入${title}`}
99+
value={value}
100+
onChange={(e) => onChange(e.target.value)}
101+
/>
67102
),
68103
},
69104
];

0 commit comments

Comments
 (0)