@wordrhyme/auto-crud 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,724 @@
1
+ # @wordrhyme/auto-crud
2
+
3
+ > Schema-first CRUD components with auto-generated tables and forms
4
+
5
+ 基于 Zod Schema 自动生成完整 CRUD 界面的低代码 React 组件库。
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@wordrhyme/auto-crud.svg)](https://www.npmjs.com/package/@wordrhyme/auto-crud)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ---
11
+
12
+ ## ✨ 特性
13
+
14
+ - 🚀 **零配置 CRUD**: 从 Zod Schema 自动生成表格和表单
15
+ - 🎨 **高级数据表格**: 基于 TanStack Table,支持排序、过滤、分页
16
+ - 📝 **智能表单**: 集成 Formily,支持复杂表单联动
17
+ - 🔌 **灵活集成**: 支持 tRPC、REST API 或内存数据源
18
+ - 🎯 **类型安全**: 完整的 TypeScript 类型推断
19
+ - 🌐 **URL 状态同步**: 使用 nuqs 实现 URL 状态管理
20
+ - 🎭 **三种过滤模式**: Simple / Advanced / Command
21
+ - 🔄 **批量操作**: 支持批量更新和删除
22
+
23
+ ---
24
+
25
+ ## 📦 安装
26
+
27
+ ```bash
28
+ # pnpm
29
+ pnpm add @wordrhyme/auto-crud zod
30
+
31
+ # npm
32
+ npm install @wordrhyme/auto-crud zod
33
+
34
+ # yarn
35
+ yarn add @wordrhyme/auto-crud zod
36
+ ```
37
+
38
+ ### Peer Dependencies
39
+
40
+ ```json
41
+ {
42
+ "react": "^18.0.0 || ^19.0.0",
43
+ "react-dom": "^18.0.0 || ^19.0.0",
44
+ "zod": "^3.0.0 || ^4.0.0"
45
+ }
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 🚀 快速开始
51
+
52
+ ### 基础示例
53
+
54
+ ```typescript
55
+ import { AutoCrudTable, useAutoCrudResource, createMemoryDataSource } from "@wordrhyme/auto-crud";
56
+ import { z } from "zod";
57
+
58
+ // 1. 定义 Zod Schema
59
+ const taskSchema = z.object({
60
+ id: z.string(),
61
+ title: z.string(),
62
+ status: z.enum(["todo", "in-progress", "done"]),
63
+ priority: z.enum(["low", "medium", "high"]),
64
+ createdAt: z.date(),
65
+ });
66
+
67
+ type Task = z.infer<typeof taskSchema>;
68
+
69
+ // 2. 创建数据源
70
+ const dataSource = createMemoryDataSource<Task>({
71
+ data: [
72
+ { id: "1", title: "Task 1", status: "todo", priority: "high", createdAt: new Date() },
73
+ { id: "2", title: "Task 2", status: "done", priority: "low", createdAt: new Date() },
74
+ ],
75
+ onCreate: async (data) => { /* 创建逻辑 */ },
76
+ onUpdate: async (id, data) => { /* 更新逻辑 */ },
77
+ onDelete: async (id) => { /* 删除逻辑 */ },
78
+ });
79
+
80
+ // 3. 使用组件
81
+ function TasksPage() {
82
+ const resource = useAutoCrudResource({
83
+ dataSource,
84
+ schema: taskSchema,
85
+ });
86
+
87
+ return (
88
+ <AutoCrudTable
89
+ title="任务管理"
90
+ schema={taskSchema}
91
+ resource={resource}
92
+ />
93
+ );
94
+ }
95
+ ```
96
+
97
+ ### 与 tRPC 集成
98
+
99
+ ```typescript
100
+ import { AutoCrudTable, useAutoCrudResource, createTRPCDataSource } from "@wordrhyme/auto-crud";
101
+ import { trpc } from "@/lib/trpc/client";
102
+ import { createSelectSchema } from "drizzle-zod";
103
+ import { tasks } from "@/db/schema";
104
+
105
+ const taskSchema = createSelectSchema(tasks);
106
+
107
+ function TasksPage() {
108
+ // URL 状态管理
109
+ const [queryParams] = useQueryStates({
110
+ page: parseAsInteger.withDefault(1),
111
+ perPage: parseAsInteger.withDefault(10),
112
+ sort: getSortingStateParser().withDefault([]),
113
+ filters: getFiltersStateParser().withDefault([]),
114
+ });
115
+
116
+ // 创建 tRPC 数据源
117
+ const dataSource = createTRPCDataSource({
118
+ router: trpc.tasks,
119
+ queryInput: queryParams,
120
+ });
121
+
122
+ const resource = useAutoCrudResource({
123
+ dataSource,
124
+ schema: taskSchema,
125
+ });
126
+
127
+ return (
128
+ <AutoCrudTable
129
+ title="任务管理"
130
+ schema={taskSchema}
131
+ resource={resource}
132
+ fieldOverrides={{
133
+ id: { hidden: true },
134
+ status: { label: "状态" },
135
+ priority: { label: "优先级" },
136
+ }}
137
+ tableProps={{
138
+ filterMode: ["simple", "advanced", "command"],
139
+ batchUpdateFields: ["status", "priority"],
140
+ }}
141
+ />
142
+ );
143
+ }
144
+ ```
145
+
146
+ ---
147
+
148
+ ## 📖 核心概念
149
+
150
+ ### Schema First 理念
151
+
152
+ ```
153
+ Zod Schema → 自动推断字段类型 → 生成表格列 + 表单字段
154
+ ```
155
+
156
+ **优势**:
157
+ - ✅ 单一数据源(SSOT)
158
+ - ✅ 类型安全
159
+ - ✅ 零手动配置
160
+ - ✅ Schema 变更自动同步
161
+
162
+ ### 数据源(Data Source)
163
+
164
+ `@wordrhyme/auto-crud` 支持三种数据源:
165
+
166
+ #### 1. 内存数据源(Memory Data Source)
167
+
168
+ 适合:原型开发、演示、测试
169
+
170
+ ```typescript
171
+ import { createMemoryDataSource } from "@wordrhyme/auto-crud";
172
+
173
+ const dataSource = createMemoryDataSource({
174
+ data: initialData,
175
+ onCreate: async (data) => { /* ... */ },
176
+ onUpdate: async (id, data) => { /* ... */ },
177
+ onDelete: async (id) => { /* ... */ },
178
+ });
179
+ ```
180
+
181
+ #### 2. tRPC 数据源(tRPC Data Source)
182
+
183
+ 适合:全栈 TypeScript 项目
184
+
185
+ ```typescript
186
+ import { createTRPCDataSource } from "@wordrhyme/auto-crud";
187
+
188
+ const dataSource = createTRPCDataSource({
189
+ router: trpc.tasks,
190
+ queryInput: { page: 1, perPage: 10 },
191
+ });
192
+ ```
193
+
194
+ **要求**:后端需要使用 `@wordrhyme/auto-crud-server` 创建 CRUD 路由。
195
+
196
+ #### 3. 自定义数据源(Custom Data Source)
197
+
198
+ 适合:REST API、GraphQL 等
199
+
200
+ ```typescript
201
+ const dataSource: DataSource<Task> = {
202
+ list: async (params) => {
203
+ const response = await fetch(`/api/tasks?${new URLSearchParams(params)}`);
204
+ return response.json();
205
+ },
206
+ get: async (id) => {
207
+ const response = await fetch(`/api/tasks/${id}`);
208
+ return response.json();
209
+ },
210
+ create: async (data) => {
211
+ const response = await fetch("/api/tasks", {
212
+ method: "POST",
213
+ body: JSON.stringify(data),
214
+ });
215
+ return response.json();
216
+ },
217
+ update: async (id, data) => {
218
+ const response = await fetch(`/api/tasks/${id}`, {
219
+ method: "PATCH",
220
+ body: JSON.stringify(data),
221
+ });
222
+ return response.json();
223
+ },
224
+ delete: async (id) => {
225
+ await fetch(`/api/tasks/${id}`, { method: "DELETE" });
226
+ },
227
+ deleteMany: async (ids) => {
228
+ await fetch("/api/tasks/batch", {
229
+ method: "DELETE",
230
+ body: JSON.stringify({ ids }),
231
+ });
232
+ },
233
+ };
234
+ ```
235
+
236
+ ---
237
+
238
+ ## 🎨 组件 API
239
+
240
+ ### `<AutoCrudTable />`
241
+
242
+ 完整的 CRUD 表格组件。
243
+
244
+ #### Props
245
+
246
+ ```typescript
247
+ interface AutoCrudTableProps<TData> {
248
+ // 必需
249
+ title: string; // 表格标题
250
+ schema: z.ZodType<TData>; // Zod Schema
251
+ resource: AutoCrudResource<TData>; // useAutoCrudResource 返回值
252
+
253
+ // 可选
254
+ fieldOverrides?: FieldOverrides<TData>; // 字段配置
255
+ tableProps?: {
256
+ filterMode?: FilterMode | FilterMode[]; // 过滤模式
257
+ batchUpdateFields?: (keyof TData)[]; // 批量更新字段
258
+ };
259
+ slots?: {
260
+ toolbarEnd?: React.ReactNode; // 工具栏右侧插槽
261
+ };
262
+ }
263
+ ```
264
+
265
+ #### 示例
266
+
267
+ ```typescript
268
+ <AutoCrudTable
269
+ title="用户管理"
270
+ schema={userSchema}
271
+ resource={resource}
272
+ fieldOverrides={{
273
+ id: { hidden: true },
274
+ email: { label: "邮箱" },
275
+ role: {
276
+ label: "角色",
277
+ table: {
278
+ meta: {
279
+ variant: "select",
280
+ options: [
281
+ { label: "管理员", value: "admin" },
282
+ { label: "用户", value: "user" },
283
+ ],
284
+ },
285
+ },
286
+ },
287
+ }}
288
+ tableProps={{
289
+ filterMode: ["simple", "advanced"],
290
+ batchUpdateFields: ["role", "status"],
291
+ }}
292
+ />
293
+ ```
294
+
295
+ ### `useAutoCrudResource()`
296
+
297
+ 连接数据源到组件的 Hook。
298
+
299
+ #### 参数
300
+
301
+ ```typescript
302
+ interface UseAutoCrudResourceConfig<TData> {
303
+ dataSource: DataSource<TData>; // 数据源
304
+ schema: z.ZodType<TData>; // Zod Schema
305
+ }
306
+ ```
307
+
308
+ #### 返回值
309
+
310
+ ```typescript
311
+ interface AutoCrudResource<TData> {
312
+ // 数据
313
+ data: TData[];
314
+ total: number;
315
+ isLoading: boolean;
316
+
317
+ // 模态框状态
318
+ modal: {
319
+ variant: "dialog" | "sheet";
320
+ isOpen: boolean;
321
+ mode: "create" | "edit";
322
+ editingItem: TData | null;
323
+ };
324
+
325
+ // 操作方法
326
+ handlers: {
327
+ setVariant: (variant: "dialog" | "sheet") => void;
328
+ openCreate: () => void;
329
+ openEdit: (item: TData) => void;
330
+ closeModal: () => void;
331
+ handleCreate: (data: Partial<TData>) => Promise<void>;
332
+ handleUpdate: (id: string, data: Partial<TData>) => Promise<void>;
333
+ handleDelete: (id: string) => Promise<void>;
334
+ handleDeleteMany: (ids: string[]) => Promise<void>;
335
+ };
336
+ }
337
+ ```
338
+
339
+ ---
340
+
341
+ ## 🔧 字段配置
342
+
343
+ ### 基础配置
344
+
345
+ ```typescript
346
+ fieldOverrides={{
347
+ fieldName: {
348
+ label: "显示名称", // 表格和表单共用
349
+ hidden: true, // 表格和表单都隐藏
350
+ },
351
+ }}
352
+ ```
353
+
354
+ ### 表格特定配置
355
+
356
+ ```typescript
357
+ fieldOverrides={{
358
+ amount: {
359
+ label: "金额",
360
+ table: {
361
+ meta: {
362
+ unit: "¥", // 单位显示
363
+ variant: "number", // 筛选器类型
364
+ },
365
+ },
366
+ },
367
+ status: {
368
+ label: "状态",
369
+ table: {
370
+ meta: {
371
+ variant: "select",
372
+ options: [
373
+ { label: "待处理", value: "pending" },
374
+ { label: "已完成", value: "completed" },
375
+ ],
376
+ },
377
+ },
378
+ },
379
+ }}
380
+ ```
381
+
382
+ ### 表单特定配置
383
+
384
+ ```typescript
385
+ fieldOverrides={{
386
+ description: {
387
+ label: "描述",
388
+ form: {
389
+ "x-component": "Textarea",
390
+ "x-component-props": { rows: 5 },
391
+ },
392
+ },
393
+ createdAt: {
394
+ label: "创建时间",
395
+ form: {
396
+ "x-hidden": true, // 仅表单隐藏
397
+ },
398
+ },
399
+ }}
400
+ ```
401
+
402
+ ### 字段联动
403
+
404
+ ```typescript
405
+ fieldOverrides={{
406
+ endDate: {
407
+ label: "结束日期",
408
+ form: {
409
+ "x-reactions": {
410
+ dependencies: ["startDate"],
411
+ when: "{{$deps[0] !== undefined}}",
412
+ fulfill: {
413
+ state: {
414
+ visible: true,
415
+ disabled: false,
416
+ },
417
+ },
418
+ },
419
+ },
420
+ },
421
+ }}
422
+ ```
423
+
424
+ ---
425
+
426
+ ## 🎯 过滤模式
427
+
428
+ ### Simple 模式(简单筛选)
429
+
430
+ - 适合:快速筛选常用字段
431
+ - 特点:下拉选择框,一键清除
432
+ - 示例:状态筛选、优先级筛选
433
+
434
+ ```typescript
435
+ tableProps={{
436
+ filterMode: "simple",
437
+ }}
438
+ ```
439
+
440
+ ### Advanced 模式(高级筛选)
441
+
442
+ - 适合:复杂多条件查询
443
+ - 特点:Notion 风格,支持 AND/OR 逻辑
444
+ - 示例:`status = "done" AND priority = "high"`
445
+
446
+ ```typescript
447
+ tableProps={{
448
+ filterMode: "advanced",
449
+ }}
450
+ ```
451
+
452
+ ### Command 模式(命令面板)
453
+
454
+ - 适合:键盘流用户
455
+ - 特点:Linear 风格,快捷键 `Cmd+K`
456
+ - 示例:快速搜索并添加筛选条件
457
+
458
+ ```typescript
459
+ tableProps={{
460
+ filterMode: "command",
461
+ }}
462
+ ```
463
+
464
+ ### 多模式切换
465
+
466
+ ```typescript
467
+ tableProps={{
468
+ filterMode: ["simple", "advanced", "command"], // 第一个为默认模式
469
+ }}
470
+ ```
471
+
472
+ ---
473
+
474
+ ## 🔄 批量操作
475
+
476
+ ### 批量更新
477
+
478
+ ```typescript
479
+ <AutoCrudTable
480
+ schema={taskSchema}
481
+ resource={resource}
482
+ tableProps={{
483
+ batchUpdateFields: ["status", "priority"],
484
+ }}
485
+ />
486
+ ```
487
+
488
+ **功能**:
489
+ - 选择多行
490
+ - 点击批量更新按钮
491
+ - 选择字段和新值
492
+ - 一键更新所有选中行
493
+
494
+ ### 批量删除
495
+
496
+ ```typescript
497
+ // 自动启用,无需配置
498
+ <AutoCrudTable schema={taskSchema} resource={resource} />
499
+ ```
500
+
501
+ **功能**:
502
+ - 选择多行
503
+ - 点击批量删除按钮
504
+ - 确认删除
505
+ - 一次性删除所有选中行
506
+
507
+ ---
508
+
509
+ ## 🎨 自定义样式
510
+
511
+ ### 使用 Tailwind CSS
512
+
513
+ ```typescript
514
+ <AutoCrudTable
515
+ schema={taskSchema}
516
+ resource={resource}
517
+ className="custom-table"
518
+ />
519
+ ```
520
+
521
+ ### 自定义工具栏
522
+
523
+ ```typescript
524
+ <AutoCrudTable
525
+ schema={taskSchema}
526
+ resource={resource}
527
+ slots={{
528
+ toolbarEnd: (
529
+ <div className="flex gap-2">
530
+ <Button onClick={handleExport}>导出</Button>
531
+ <Button onClick={handleImport}>导入</Button>
532
+ </div>
533
+ ),
534
+ }}
535
+ />
536
+ ```
537
+
538
+ ---
539
+
540
+ ## 📚 高级用法
541
+
542
+ ### 自定义列渲染
543
+
544
+ ```typescript
545
+ import { createColumns } from "@wordrhyme/auto-crud";
546
+
547
+ const columns = createColumns(taskSchema, {
548
+ overrides: {
549
+ status: {
550
+ cell: ({ row }) => (
551
+ <Badge variant={row.original.status === "done" ? "success" : "default"}>
552
+ {row.original.status}
553
+ </Badge>
554
+ ),
555
+ },
556
+ },
557
+ });
558
+ ```
559
+
560
+ ### 自定义表单组件
561
+
562
+ ```typescript
563
+ fieldOverrides={{
564
+ tags: {
565
+ label: "标签",
566
+ form: {
567
+ "x-component": "TagsInput",
568
+ "x-component-props": {
569
+ placeholder: "输入标签",
570
+ maxTags: 5,
571
+ },
572
+ },
573
+ },
574
+ }}
575
+ ```
576
+
577
+ ### 服务端分页
578
+
579
+ ```typescript
580
+ const [queryParams] = useQueryStates({
581
+ page: parseAsInteger.withDefault(1),
582
+ perPage: parseAsInteger.withDefault(10),
583
+ });
584
+
585
+ const dataSource = createTRPCDataSource({
586
+ router: trpc.tasks,
587
+ queryInput: queryParams,
588
+ });
589
+ ```
590
+
591
+ ---
592
+
593
+ ## 🔌 与其他库集成
594
+
595
+ ### 与 Drizzle ORM 集成
596
+
597
+ ```typescript
598
+ import { createSelectSchema } from "drizzle-zod";
599
+ import { tasks } from "@/db/schema";
600
+
601
+ const taskSchema = createSelectSchema(tasks);
602
+
603
+ <AutoCrudTable schema={taskSchema} resource={resource} />
604
+ ```
605
+
606
+ ### 与 React Hook Form 集成
607
+
608
+ ```typescript
609
+ import { zodResolver } from "@hookform/resolvers/zod";
610
+ import { useForm } from "react-hook-form";
611
+
612
+ const form = useForm({
613
+ resolver: zodResolver(taskSchema),
614
+ });
615
+ ```
616
+
617
+ ### 与 Next.js 集成
618
+
619
+ ```typescript
620
+ // app/tasks/page.tsx
621
+ "use client";
622
+
623
+ import { AutoCrudTable } from "@wordrhyme/auto-crud";
624
+
625
+ export default function TasksPage() {
626
+ return <AutoCrudTable schema={taskSchema} resource={resource} />;
627
+ }
628
+ ```
629
+
630
+ ---
631
+
632
+ ## 🛠️ 工具函数
633
+
634
+ ### `createColumns()`
635
+
636
+ 从 Zod Schema 自动生成表格列。
637
+
638
+ ```typescript
639
+ import { createColumns } from "@wordrhyme/auto-crud";
640
+
641
+ const columns = createColumns(taskSchema, {
642
+ exclude: ["id", "createdAt"],
643
+ overrides: {
644
+ status: {
645
+ meta: {
646
+ label: "状态",
647
+ variant: "select",
648
+ },
649
+ },
650
+ },
651
+ });
652
+ ```
653
+
654
+ ### `createFormSchema()`
655
+
656
+ 从 Zod Schema 自动生成 Formily 表单 Schema。
657
+
658
+ ```typescript
659
+ import { createFormSchema } from "@wordrhyme/auto-crud";
660
+
661
+ const formSchema = createFormSchema(taskSchema, {
662
+ exclude: ["id", "createdAt"],
663
+ layout: "vertical",
664
+ });
665
+ ```
666
+
667
+ ---
668
+
669
+ ## 📦 导出的类型
670
+
671
+ ```typescript
672
+ // 组件
673
+ export { AutoCrudTable } from "./components/auto-crud/auto-crud-table";
674
+ export { AutoForm } from "./components/auto-crud/auto-form";
675
+ export { AutoTable } from "./components/auto-crud/auto-table";
676
+
677
+ // Hooks
678
+ export { useAutoCrudResource } from "./hooks/use-auto-crud-resource";
679
+ export { useDataTable } from "./hooks/use-data-table";
680
+
681
+ // 数据源
682
+ export { createTRPCDataSource, createMemoryDataSource } from "./lib/data-source";
683
+ export type { DataSource, ListParams, ListResult } from "./lib/data-source";
684
+
685
+ // 工具函数
686
+ export { createColumns, createFormSchema } from "./lib/schema-bridge";
687
+ export type {
688
+ FieldOverrides,
689
+ FieldOverride,
690
+ CreateColumnsOptions,
691
+ CreateFormSchemaOptions,
692
+ } from "./lib/schema-bridge";
693
+ ```
694
+
695
+ ---
696
+
697
+ ## 🤝 贡献
698
+
699
+ 欢迎贡献代码!请查看 [CONTRIBUTING.md](./CONTRIBUTING.md)。
700
+
701
+ ---
702
+
703
+ ## 📄 许可证
704
+
705
+ MIT © [wordrhyme](https://github.com/pixpilot/shadcn-components)
706
+
707
+ ---
708
+
709
+ ## 🔗 相关链接
710
+
711
+ - [GitHub](https://github.com/pixpilot/shadcn-components)
712
+ - [文档](https://github.com/pixpilot/shadcn-components/tree/main/packages/auto-crud)
713
+ - [示例](https://github.com/pixpilot/shadcn-components/tree/main/examples)
714
+ - [Changelog](./CHANGELOG.md)
715
+
716
+ ---
717
+
718
+ ## 💡 灵感来源
719
+
720
+ - [TanStack Table](https://tanstack.com/table) - 强大的表格库
721
+ - [Formily](https://formilyjs.org/) - 灵活的表单解决方案
722
+ - [Shadcn UI](https://ui.shadcn.com/) - 优雅的 UI 组件
723
+ - [Notion](https://notion.so) - 高级筛选器设计
724
+ - [Linear](https://linear.app) - 命令面板设计