imean-service-engine-htmx-plugin 2.3.1 → 2.5.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/dist/index.d.mts CHANGED
@@ -2,47 +2,137 @@ import { Context } from 'hono';
2
2
  import { z } from 'zod';
3
3
  import { Plugin, PluginPriority, Microservice } from 'imean-service-engine';
4
4
  import * as hono_jsx_jsx_dev_runtime from 'hono/jsx/jsx-dev-runtime';
5
- import * as hono_utils_html from 'hono/utils/html';
6
5
 
7
6
  /**
8
- * HtmxAdminPlugin 核心类型定义
7
+ * 组件系统上下文
8
+ * 提供渲染上下文和组件上下文
9
9
  */
10
10
 
11
+ declare class RenderContext<TProps = any, TState = any> {
12
+ readonly prefix: string;
13
+ readonly instanceId: string;
14
+ readonly componentName: string;
15
+ constructor(prefix: string, instanceId: string, componentName: string);
16
+ $id(): string;
17
+ setState(state: Partial<TState>): void;
18
+ get state(): TState;
19
+ get props(): TProps;
20
+ url(methodName: string, params?: Record<string, any>): string;
21
+ callMethod(methodName: string, params: Record<string, string>): any;
22
+ }
23
+ declare class ComponentContext extends RenderContext {
24
+ readonly ctx: Context;
25
+ constructor(prefix: string, ctx: Context, componentName: string);
26
+ params(): Promise<Record<string, any>>;
27
+ query(): Record<string, string>;
28
+ body(): Promise<any>;
29
+ }
30
+
11
31
  /**
12
- * 操作按钮配置
32
+ * 组件系统核心
33
+ * 提供组件基类、方法装饰器和组件注册功能
13
34
  */
14
- interface ActionButton {
15
- /** 按钮文本 */
16
- label: string;
17
- /** 链接地址(页面模式使用) */
18
- href?: string;
19
- /** HTTP 方法 */
35
+
36
+ interface MethodConfig {
20
37
  method?: "get" | "post" | "put" | "delete";
21
- /** 按钮样式 */
22
- variant?: "primary" | "secondary" | "danger" | "ghost";
23
- /** HTMX GET 请求(弹窗模式使用) */
24
- hxGet?: string;
25
- /** HTMX POST 请求 */
26
- hxPost?: string;
27
- /** HTMX PUT 请求 */
28
- hxPut?: string;
29
- /** HTMX DELETE 请求 */
30
- hxDelete?: string;
31
- /** 确认提示 */
32
- confirm?: string;
33
- /** 是否关闭弹窗(设置为 true 时,点击按钮会自动关闭弹窗,无需写 Hyperscript 代码) */
34
- close?: boolean;
35
- /** 是否提交表单(设置为 true 时,按钮会提交指定的表单,需要配合 formId 使用) */
36
- submit?: boolean;
37
- /** 表单 ID(当 submit 为 true 时,指定要提交的表单 ID) */
38
- formId?: string;
39
- /** 自定义点击事件(如关闭弹窗,当 close 为 true 时此属性会被忽略) */
40
- onClick?: string;
41
- /** 自定义类名 */
42
- className?: string;
43
- /** 链接目标(如 "_blank" 表示新窗口打开) */
44
- target?: string;
38
+ path?: string;
39
+ }
40
+ declare function Method(config?: MethodConfig): (target: any, propertyKey: string, _descriptor: PropertyDescriptor) => void;
41
+ declare abstract class HtmxComponent<TProps = any> {
42
+ readonly name: string;
43
+ prefix: string;
44
+ constructor(name: string);
45
+ readonly Component: (props: TProps) => any;
46
+ protected abstract render(ctx: RenderContext, props: TProps): any;
47
+ getScript?(): any;
48
+ static getMethods(component: HtmxComponent<any>): Map<string, {
49
+ method: "get" | "post" | "put" | "delete";
50
+ path?: string;
51
+ handler: (ctx: ComponentContext) => Promise<Response>;
52
+ }>;
45
53
  }
54
+
55
+ /**
56
+ * Feature 注册表
57
+ */
58
+
59
+ /**
60
+ * Feature 注册表
61
+ * 类型通过 model.schema 的 z.infer 推断
62
+ */
63
+ declare class FeatureRegistry {
64
+ private features;
65
+ private model;
66
+ constructor(model: PageModel);
67
+ /**
68
+ * 注册 Feature
69
+ */
70
+ register(name: string, feature: Feature): void;
71
+ /**
72
+ * 快捷方法:注册列表 Feature
73
+ */
74
+ list(feature: Feature): void;
75
+ /**
76
+ * 快捷方法:注册详情 Feature
77
+ */
78
+ detail(feature: Feature): void;
79
+ /**
80
+ * 快捷方法:注册创建 Feature
81
+ */
82
+ create(feature: Feature): void;
83
+ /**
84
+ * 快捷方法:注册编辑 Feature
85
+ */
86
+ edit(feature: Feature): void;
87
+ /**
88
+ * 快捷方法:注册删除 Feature
89
+ */
90
+ delete(feature: Feature): void;
91
+ /**
92
+ * 快捷方法:注册自定义 Feature
93
+ */
94
+ custom(name: string, feature: Feature): void;
95
+ /**
96
+ * 获取所有注册的 Feature
97
+ */
98
+ getAll(): Feature[];
99
+ /**
100
+ * 获取指定 Feature
101
+ */
102
+ get(name: string): Feature | undefined;
103
+ }
104
+
105
+ /**
106
+ * PageModel 基类
107
+ * 统一处理有数据模型和无数据模型的场景
108
+ */
109
+
110
+ /**
111
+ * PageModel 基类
112
+ * 不再包含 schema,schema 由各个 Feature 指定
113
+ */
114
+ declare abstract class PageModel {
115
+ readonly modelName: string;
116
+ readonly features: FeatureRegistry;
117
+ private metadata;
118
+ /**
119
+ * 构造函数
120
+ * @param modelName 模型/页面名称(用于路由和权限)
121
+ * @param metadata 页面元数据(可选,如果提供则不需要实现 getMetadata)
122
+ */
123
+ constructor(modelName: string, metadata?: PageMetadata);
124
+ /**
125
+ * 获取页面元数据
126
+ * 如果构造函数提供了 metadata,直接返回
127
+ * 否则调用子类实现
128
+ */
129
+ getMetadata(): PageMetadata;
130
+ }
131
+
132
+ /**
133
+ * HtmxAdminPlugin 核心类型定义
134
+ */
135
+
46
136
  /**
47
137
  * 对话框大小类型
48
138
  */
@@ -209,8 +299,8 @@ interface Feature {
209
299
  getTitle?(context: FeatureContext): string | Promise<string>;
210
300
  /** 获取动态描述(可选,会覆盖 PageMetadata 的 description) */
211
301
  getDescription?(context: FeatureContext): string | Promise<string> | undefined | Promise<string | undefined>;
212
- /** 获取操作按钮(可选,根据 isDialog 返回不同的按钮配置) */
213
- getActions?(context: FeatureContext): ActionButton[] | Promise<ActionButton[]>;
302
+ /** 获取操作按钮(可选,返回 JSX,用于在 layout 中渲染) */
303
+ getActions?(context: FeatureContext): any | Promise<any>;
214
304
  /** 路由配置(必须实现) */
215
305
  getRoutes(): Array<{
216
306
  method: "get" | "post" | "put" | "delete";
@@ -306,7 +396,21 @@ interface HtmxAdminPluginOptions {
306
396
  navigation?: NavItemConfig[];
307
397
  /** 认证提供者(用于鉴权和权限控制) */
308
398
  authProvider?: AuthProvider;
399
+ /** 组件配置(可选,用于注册组件) */
400
+ components?: HtmxComponent<any>[];
401
+ /** 页面配置(可选,用于注册页面) */
402
+ pages: PageModel[];
309
403
  }
404
+ /**
405
+ * 已解析的插件配置选项(已处理默认值,所有必需字段都是非可选的)
406
+ *
407
+ * 设计原则:如果在上层已经处理了默认值,那么向下传递时就不应该是可选类型。
408
+ * 这样可以:
409
+ * - 避免重复的默认值处理
410
+ * - 让类型系统更准确地反映实际的数据状态
411
+ * - 减少类型错误和运行时检查
412
+ */
413
+ type ResolvedHtmxAdminPluginOptions = Required<Pick<HtmxAdminPluginOptions, "title" | "prefix" | "navigation" | "pages" | "components">> & Pick<HtmxAdminPluginOptions, "logo" | "homePath" | "authProvider" | "pages" | "components">;
310
414
  /**
311
415
  * 导航项配置
312
416
  */
@@ -351,83 +455,6 @@ interface FormFieldRendererProps<T = any> {
351
455
  fieldName: string;
352
456
  }
353
457
 
354
- /**
355
- * Feature 注册表
356
- */
357
-
358
- /**
359
- * Feature 注册表
360
- * 类型通过 model.schema 的 z.infer 推断
361
- */
362
- declare class FeatureRegistry {
363
- private features;
364
- private model;
365
- constructor(model: PageModel);
366
- /**
367
- * 注册 Feature
368
- */
369
- register(name: string, feature: Feature): void;
370
- /**
371
- * 快捷方法:注册列表 Feature
372
- */
373
- list(feature: Feature): void;
374
- /**
375
- * 快捷方法:注册详情 Feature
376
- */
377
- detail(feature: Feature): void;
378
- /**
379
- * 快捷方法:注册创建 Feature
380
- */
381
- create(feature: Feature): void;
382
- /**
383
- * 快捷方法:注册编辑 Feature
384
- */
385
- edit(feature: Feature): void;
386
- /**
387
- * 快捷方法:注册删除 Feature
388
- */
389
- delete(feature: Feature): void;
390
- /**
391
- * 快捷方法:注册自定义 Feature
392
- */
393
- custom(name: string, feature: Feature): void;
394
- /**
395
- * 获取所有注册的 Feature
396
- */
397
- getAll(): Feature[];
398
- /**
399
- * 获取指定 Feature
400
- */
401
- get(name: string): Feature | undefined;
402
- }
403
-
404
- /**
405
- * PageModel 基类
406
- * 统一处理有数据模型和无数据模型的场景
407
- */
408
-
409
- /**
410
- * PageModel 基类
411
- * 不再包含 schema,schema 由各个 Feature 指定
412
- */
413
- declare abstract class PageModel {
414
- readonly modelName: string;
415
- readonly features: FeatureRegistry;
416
- private metadata;
417
- /**
418
- * 构造函数
419
- * @param modelName 模型/页面名称(用于路由和权限)
420
- * @param metadata 页面元数据(可选,如果提供则不需要实现 getMetadata)
421
- */
422
- constructor(modelName: string, metadata?: PageMetadata);
423
- /**
424
- * 获取页面元数据
425
- * 如果构造函数提供了 metadata,直接返回
426
- * 否则调用子类实现
427
- */
428
- getMetadata(): PageMetadata;
429
- }
430
-
431
458
  /**
432
459
  * Feature 基类
433
460
  * 提供所有 Feature 的公共属性和默认实现
@@ -470,10 +497,10 @@ declare abstract class BaseFeature implements Feature {
470
497
  */
471
498
  getDescription(context: FeatureContext): Promise<string | undefined>;
472
499
  /**
473
- * 获取操作按钮(默认实现:返回空数组)
474
- * 子类可以覆盖此方法以提供操作按钮
500
+ * 获取操作按钮(默认实现:返回 null)
501
+ * 子类可以覆盖此方法以提供操作按钮(返回 JSX)
475
502
  */
476
- getActions(context: FeatureContext): Promise<ActionButton[]>;
503
+ getActions(context: FeatureContext): Promise<any>;
477
504
  /**
478
505
  * 获取路由配置(必须实现)
479
506
  */
@@ -482,11 +509,11 @@ declare abstract class BaseFeature implements Feature {
482
509
  path: string;
483
510
  }>;
484
511
  /**
485
- * 处理请求(可选,如果实现了 handle,则优先使用 handle)
512
+ * 处理请求
486
513
  */
487
- handle?(context: FeatureContext): Promise<any>;
514
+ handle(context: FeatureContext): Promise<any>;
488
515
  /**
489
- * 渲染页面(可选,如果 handle 不存在或返回 undefined,则使用 render)
516
+ * 渲染页面
490
517
  */
491
518
  render?(context: FeatureContext): Promise<any>;
492
519
  }
@@ -569,9 +596,9 @@ declare abstract class BaseFormFeature<T extends {
569
596
  */
570
597
  render(context: FeatureContext, initialData?: Partial<T>): Promise<any>;
571
598
  /**
572
- * 获取操作按钮
599
+ * 获取操作按钮(返回 JSX)
573
600
  */
574
- getActions(context: FeatureContext): Promise<ActionButton[]>;
601
+ getActions(context: FeatureContext): Promise<any>;
575
602
  }
576
603
 
577
604
  /**
@@ -692,7 +719,6 @@ declare class DefaultDetailFeature<T extends {
692
719
  id: string | number;
693
720
  } = any> extends BaseFeature {
694
721
  private getItem;
695
- private deleteItem?;
696
722
  private titleGetter?;
697
723
  private descriptionGetter?;
698
724
  private detailFieldNames?;
@@ -702,7 +728,6 @@ declare class DefaultDetailFeature<T extends {
702
728
  /** 详情数据的 Schema(用于字段推断和显示) */
703
729
  schema: z.ZodObject<any>;
704
730
  getItem: (id: string | number) => Promise<T | null>;
705
- deleteItem?: (id: string | number) => Promise<boolean>;
706
731
  permissionPrefix: string;
707
732
  permission?: string;
708
733
  dialogSize?: DialogSize;
@@ -725,7 +750,7 @@ declare class DefaultDetailFeature<T extends {
725
750
  path: string;
726
751
  }[];
727
752
  render(context: FeatureContext): Promise<any>;
728
- getActions(context: FeatureContext): Promise<ActionButton[]>;
753
+ getActions(context: FeatureContext): Promise<any>;
729
754
  }
730
755
 
731
756
  /**
@@ -830,7 +855,7 @@ declare class DefaultListFeature<T extends {
830
855
  path: string;
831
856
  }[];
832
857
  render(context: FeatureContext): Promise<any>;
833
- getActions(context: FeatureContext): Promise<ActionButton[]>;
858
+ getActions(context: FeatureContext): Promise<any>;
834
859
  }
835
860
 
836
861
  /**
@@ -846,18 +871,16 @@ declare class HtmxAdminPlugin implements Plugin {
846
871
  readonly priority = PluginPriority.ROUTE;
847
872
  private engine;
848
873
  private hono;
849
- private options;
874
+ readonly options: ResolvedHtmxAdminPluginOptions;
850
875
  private serviceName;
851
876
  private pages;
877
+ private componentHandler;
852
878
  constructor(options?: HtmxAdminPluginOptions);
879
+ private initPages;
853
880
  /**
854
- * 注册页面(统一接口,支持有模型和无模型)
855
- */
856
- registerPage(page: PageModel): this;
857
- /**
858
- * 批量注册页面
881
+ * 注册页面
859
882
  */
860
- registerPages(...pages: PageModel[]): this;
883
+ private registerPage;
861
884
  /**
862
885
  * 引擎初始化钩子
863
886
  */
@@ -908,6 +931,9 @@ interface PermissionCheckResult {
908
931
  */
909
932
  declare function checkUserPermission(requiredPermission: string | null, userPermissions: string[]): PermissionCheckResult;
910
933
 
934
+ /**
935
+ * 对话框组件(Modal/Dialog)
936
+ */
911
937
  interface DialogProps {
912
938
  /** 对话框标题 */
913
939
  title?: string;
@@ -921,11 +947,15 @@ interface DialogProps {
921
947
  size?: "sm" | "md" | "lg" | "xl" | "full";
922
948
  /** 是否允许点击遮罩区域关闭(默认 true,设置为 false 时只能通过关闭按钮关闭) */
923
949
  closeOnBackdropClick?: boolean;
924
- /** 操作按钮(在 Footer 中显示,固定在底部) */
925
- actions?: ActionButton[];
950
+ /** 操作按钮(在 Footer 中显示,固定在底部,通过 JSX 方式渲染) */
951
+ actions?: any;
926
952
  /** 是否固定内容区域高度(用于表单等需要固定高度的场景,避免切换 Tab 时高度变化) */
927
953
  fixedContentHeight?: boolean;
928
954
  }
955
+ /**
956
+ * 对话框组件
957
+ * 用于在模态框中显示内容,支持 HTMX 交互
958
+ */
929
959
  declare function Dialog(props: DialogProps): hono_jsx_jsx_dev_runtime.JSX.Element;
930
960
 
931
961
  /**
@@ -973,9 +1003,15 @@ interface ObjectEditorProps {
973
1003
  declare function ObjectEditor(props: ObjectEditorProps): hono_jsx_jsx_dev_runtime.JSX.Element;
974
1004
 
975
1005
  /**
976
- * 字符串数组编辑器组件
977
- * 支持增加、删除和拖放排序功能
978
- * 使用 Alpine.js 管理状态,通过隐藏字段与表单系统同步数据
1006
+ * 字符串数组编辑器组件(Alpine.js 版本)
1007
+ * 使用 Alpine.js 实现纯 JSX 交互式组件
1008
+ *
1009
+ * 设计原则:
1010
+ * - 使用 Alpine.js 的 x-data 定义状态
1011
+ * - 尽量使用声明式语法,避免在 HTML 中写方法
1012
+ * - 使用 x-model、x-show、x-for 等 Alpine.js 指令
1013
+ * - 支持拖放排序(使用 SortableList 组件)
1014
+ * - 表单提交:通过 form-data-processor 自动解析嵌套结构和压缩数组索引
979
1015
  */
980
1016
  interface StringArrayEditorProps {
981
1017
  /** 字段定义 */
@@ -990,14 +1026,25 @@ interface StringArrayEditorProps {
990
1026
  placeholder?: string;
991
1027
  /** 是否允许空值(默认 false) */
992
1028
  allowEmpty?: boolean;
1029
+ /** 输入框行数(默认 1,大于 1 时使用 textarea) */
1030
+ rows?: number;
993
1031
  }
994
- declare function StringArrayEditor(props: StringArrayEditorProps): hono_utils_html.HtmlEscapedString | Promise<hono_utils_html.HtmlEscapedString>;
1032
+ /**
1033
+ * 字符串数组编辑器组件(Alpine.js 版本)
1034
+ * 使用 Alpine.js 的 x-data 和指令实现交互
1035
+ */
1036
+ declare function StringArrayEditor(props: StringArrayEditorProps): hono_jsx_jsx_dev_runtime.JSX.Element;
995
1037
 
996
1038
  /**
997
- * 标签编辑器组件
998
- * 支持增加、删除和拖放排序功能
999
- * 使用更紧凑的标签样式布局,适合维护 tags
1000
- * 使用 Alpine.js 管理状态,通过隐藏字段与表单系统同步数据
1039
+ * 标签编辑器组件(Alpine.js 版本)
1040
+ * 使用 Alpine.js 实现纯 JSX 交互式组件
1041
+ *
1042
+ * 设计原则:
1043
+ * - 使用 Alpine.js 的 x-data 定义状态
1044
+ * - 尽量使用声明式语法,避免在 HTML 中写方法
1045
+ * - 使用 x-model、x-show、x-for 等 Alpine.js 指令
1046
+ * - 支持拖放排序(使用 SortableList 组件)
1047
+ * - 表单提交:通过 form-data-processor 自动解析嵌套结构和压缩数组索引
1001
1048
  */
1002
1049
  interface TagsEditorProps {
1003
1050
  /** 字段定义 */
@@ -1013,6 +1060,47 @@ interface TagsEditorProps {
1013
1060
  /** 是否允许空值(默认 false) */
1014
1061
  allowEmpty?: boolean;
1015
1062
  }
1016
- declare function TagsEditor(props: TagsEditorProps): hono_utils_html.HtmlEscapedString | Promise<hono_utils_html.HtmlEscapedString>;
1063
+ /**
1064
+ * 标签编辑器组件(Alpine.js 版本)
1065
+ * 使用 Alpine.js 的 x-data 和指令实现交互
1066
+ */
1067
+ declare function TagsEditor(props: TagsEditorProps): hono_jsx_jsx_dev_runtime.JSX.Element;
1068
+
1069
+ /**
1070
+ * 可拖拽排序列表组件
1071
+ * 使用 HTML5 原生拖放 API 实现拖拽排序
1072
+ *
1073
+ * 设计原则:
1074
+ * - 使用 Alpine.js 管理状态和事件处理
1075
+ * - 使用 HTML5 原生拖放 API(draggable、x-on:dragstart、x-on:dragover、x-on:drop)
1076
+ * - 高阶组件,可以包裹任何子元素
1077
+ * - 使用事件委托,在容器上统一处理所有拖拽事件
1078
+ * - 所有事件处理使用 Alpine.js 声明式语法
1079
+ */
1080
+ interface SortableListProps {
1081
+ /** 子元素 */
1082
+ children: any;
1083
+ /** 自定义类名 */
1084
+ className?: string;
1085
+ /** 拖拽手柄选择器(可选,如果提供,只有手柄可拖拽) */
1086
+ handle?: string;
1087
+ /** 拖拽时的样式类名(可选) */
1088
+ draggingClass?: string;
1089
+ /** 拖拽悬停时的样式类名(可选) */
1090
+ dragOverClass?: string;
1091
+ /** 排序变化回调(可选) */
1092
+ onSortableChange?: (detail: {
1093
+ oldIndex: number;
1094
+ newIndex: number;
1095
+ }) => void;
1096
+ /** 其他属性 */
1097
+ [key: string]: any;
1098
+ }
1099
+ /**
1100
+ * 可拖拽排序列表组件
1101
+ * 使用 HTML5 原生拖放 API 和 Alpine.js 声明式语法
1102
+ * 使用事件委托在容器上统一处理所有拖拽事件
1103
+ */
1104
+ declare function SortableList(props: SortableListProps): hono_jsx_jsx_dev_runtime.JSX.Element;
1017
1105
 
1018
- export { type AuthProvider, BaseFeature, CustomFeature, DefaultCreateFeature, DefaultDeleteFeature, DefaultDetailFeature, DefaultEditFeature, DefaultListFeature, Dialog, type DialogProps, type DialogSize, ErrorAlert, type ErrorAlertProps, type Feature, type FeatureContext, type FeatureType, type FieldMetadata, HtmxAdminPlugin, type HtmxAdminPluginOptions, type ListParams, type ListResult, LoadingBar, type NavItemConfig, type Notification, type NotificationType, ObjectEditor, type ObjectEditorProps, type PageMetadata, PageModel, type PermissionResult, StringArrayEditor, type StringArrayEditorProps, TagsEditor, type TagsEditorProps, type UserInfo, checkUserPermission, getUserInfo, modelNameToPath, parseListParams };
1106
+ export { type AuthProvider, BaseFeature, ComponentContext, CustomFeature, DefaultCreateFeature, DefaultDeleteFeature, DefaultDetailFeature, DefaultEditFeature, DefaultListFeature, Dialog, type DialogProps, type DialogSize, ErrorAlert, type ErrorAlertProps, type Feature, type FeatureContext, type FeatureType, type FieldMetadata, HtmxAdminPlugin, type HtmxAdminPluginOptions, HtmxComponent, type ListParams, type ListResult, LoadingBar, Method, type NavItemConfig, type Notification, type NotificationType, ObjectEditor, type ObjectEditorProps, type PageMetadata, PageModel, type PermissionResult, RenderContext, SortableList, StringArrayEditor, type StringArrayEditorProps, TagsEditor, type TagsEditorProps, type UserInfo, checkUserPermission, getUserInfo, modelNameToPath, parseListParams };