@h-ai/ui 0.1.0-alpha5

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.
Files changed (234) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +488 -0
  3. package/auto-import.d.ts +96 -0
  4. package/auto-import.js +259 -0
  5. package/dist/components/compounds/Accordion.svelte +142 -0
  6. package/dist/components/compounds/Accordion.svelte.d.ts +25 -0
  7. package/dist/components/compounds/ActionSheet.svelte +116 -0
  8. package/dist/components/compounds/ActionSheet.svelte.d.ts +22 -0
  9. package/dist/components/compounds/Alert.svelte +67 -0
  10. package/dist/components/compounds/Alert.svelte.d.ts +8 -0
  11. package/dist/components/compounds/AppBar.svelte +77 -0
  12. package/dist/components/compounds/AppBar.svelte.d.ts +20 -0
  13. package/dist/components/compounds/BottomNav.svelte +75 -0
  14. package/dist/components/compounds/BottomNav.svelte.d.ts +18 -0
  15. package/dist/components/compounds/Breadcrumb.svelte +49 -0
  16. package/dist/components/compounds/Breadcrumb.svelte.d.ts +4 -0
  17. package/dist/components/compounds/Calendar.svelte +116 -0
  18. package/dist/components/compounds/Calendar.svelte.d.ts +47 -0
  19. package/dist/components/compounds/Card.svelte +77 -0
  20. package/dist/components/compounds/Card.svelte.d.ts +8 -0
  21. package/dist/components/compounds/Combobox.svelte +327 -0
  22. package/dist/components/compounds/Combobox.svelte.d.ts +69 -0
  23. package/dist/components/compounds/Confirm.svelte +90 -0
  24. package/dist/components/compounds/Confirm.svelte.d.ts +4 -0
  25. package/dist/components/compounds/DataTable.svelte +133 -0
  26. package/dist/components/compounds/DataTable.svelte.d.ts +69 -0
  27. package/dist/components/compounds/DatePicker.svelte +135 -0
  28. package/dist/components/compounds/DatePicker.svelte.d.ts +46 -0
  29. package/dist/components/compounds/Drawer.svelte +113 -0
  30. package/dist/components/compounds/Drawer.svelte.d.ts +4 -0
  31. package/dist/components/compounds/Dropdown.svelte +91 -0
  32. package/dist/components/compounds/Dropdown.svelte.d.ts +8 -0
  33. package/dist/components/compounds/Empty.svelte +83 -0
  34. package/dist/components/compounds/Empty.svelte.d.ts +4 -0
  35. package/dist/components/compounds/Form.svelte +96 -0
  36. package/dist/components/compounds/Form.svelte.d.ts +7 -0
  37. package/dist/components/compounds/FormField.svelte +56 -0
  38. package/dist/components/compounds/FormField.svelte.d.ts +4 -0
  39. package/dist/components/compounds/InfiniteScroll.svelte +82 -0
  40. package/dist/components/compounds/InfiniteScroll.svelte.d.ts +22 -0
  41. package/dist/components/compounds/Modal.svelte +123 -0
  42. package/dist/components/compounds/Modal.svelte.d.ts +8 -0
  43. package/dist/components/compounds/PageHeader.svelte +44 -0
  44. package/dist/components/compounds/PageHeader.svelte.d.ts +28 -0
  45. package/dist/components/compounds/Pagination.svelte +157 -0
  46. package/dist/components/compounds/Pagination.svelte.d.ts +4 -0
  47. package/dist/components/compounds/Popover.svelte +137 -0
  48. package/dist/components/compounds/Popover.svelte.d.ts +4 -0
  49. package/dist/components/compounds/PullRefresh.svelte +98 -0
  50. package/dist/components/compounds/PullRefresh.svelte.d.ts +16 -0
  51. package/dist/components/compounds/Result.svelte +84 -0
  52. package/dist/components/compounds/Result.svelte.d.ts +4 -0
  53. package/dist/components/compounds/SafeArea.svelte +37 -0
  54. package/dist/components/compounds/SafeArea.svelte.d.ts +12 -0
  55. package/dist/components/compounds/Skeleton.svelte +75 -0
  56. package/dist/components/compounds/Skeleton.svelte.d.ts +8 -0
  57. package/dist/components/compounds/Steps.svelte +111 -0
  58. package/dist/components/compounds/Steps.svelte.d.ts +4 -0
  59. package/dist/components/compounds/SwipeCell.svelte +115 -0
  60. package/dist/components/compounds/SwipeCell.svelte.d.ts +19 -0
  61. package/dist/components/compounds/Tabs.svelte +79 -0
  62. package/dist/components/compounds/Tabs.svelte.d.ts +8 -0
  63. package/dist/components/compounds/TagInput.svelte +108 -0
  64. package/dist/components/compounds/TagInput.svelte.d.ts +4 -0
  65. package/dist/components/compounds/Timeline.svelte +167 -0
  66. package/dist/components/compounds/Timeline.svelte.d.ts +25 -0
  67. package/dist/components/compounds/ToastContainer.svelte +59 -0
  68. package/dist/components/compounds/ToastContainer.svelte.d.ts +3 -0
  69. package/dist/components/compounds/Tooltip.svelte +41 -0
  70. package/dist/components/compounds/Tooltip.svelte.d.ts +4 -0
  71. package/dist/components/compounds/accordion-types.d.ts +16 -0
  72. package/dist/components/compounds/accordion-types.js +5 -0
  73. package/dist/components/compounds/action-sheet-types.d.ts +14 -0
  74. package/dist/components/compounds/action-sheet-types.js +5 -0
  75. package/dist/components/compounds/bottom-nav-types.d.ts +17 -0
  76. package/dist/components/compounds/bottom-nav-types.js +5 -0
  77. package/dist/components/compounds/index.d.ts +44 -0
  78. package/dist/components/compounds/index.js +54 -0
  79. package/dist/components/compounds/swipe-cell-types.d.ts +14 -0
  80. package/dist/components/compounds/swipe-cell-types.js +5 -0
  81. package/dist/components/compounds/timeline-types.d.ts +20 -0
  82. package/dist/components/compounds/timeline-types.js +5 -0
  83. package/dist/components/index.d.ts +9 -0
  84. package/dist/components/index.js +12 -0
  85. package/dist/components/primitives/Avatar.svelte +102 -0
  86. package/dist/components/primitives/Avatar.svelte.d.ts +8 -0
  87. package/dist/components/primitives/Badge.svelte +33 -0
  88. package/dist/components/primitives/Badge.svelte.d.ts +8 -0
  89. package/dist/components/primitives/BareButton.svelte +45 -0
  90. package/dist/components/primitives/BareButton.svelte.d.ts +4 -0
  91. package/dist/components/primitives/BareInput.svelte +101 -0
  92. package/dist/components/primitives/BareInput.svelte.d.ts +4 -0
  93. package/dist/components/primitives/Button.svelte +60 -0
  94. package/dist/components/primitives/Button.svelte.d.ts +8 -0
  95. package/dist/components/primitives/Checkbox.svelte +58 -0
  96. package/dist/components/primitives/Checkbox.svelte.d.ts +4 -0
  97. package/dist/components/primitives/IconButton.svelte +105 -0
  98. package/dist/components/primitives/IconButton.svelte.d.ts +4 -0
  99. package/dist/components/primitives/Input.svelte +130 -0
  100. package/dist/components/primitives/Input.svelte.d.ts +8 -0
  101. package/dist/components/primitives/Progress.svelte +58 -0
  102. package/dist/components/primitives/Progress.svelte.d.ts +4 -0
  103. package/dist/components/primitives/Radio.svelte +60 -0
  104. package/dist/components/primitives/Radio.svelte.d.ts +25 -0
  105. package/dist/components/primitives/Range.svelte +117 -0
  106. package/dist/components/primitives/Range.svelte.d.ts +27 -0
  107. package/dist/components/primitives/Rating.svelte +148 -0
  108. package/dist/components/primitives/Rating.svelte.d.ts +27 -0
  109. package/dist/components/primitives/Select.svelte +95 -0
  110. package/dist/components/primitives/Select.svelte.d.ts +25 -0
  111. package/dist/components/primitives/Spinner.svelte +54 -0
  112. package/dist/components/primitives/Spinner.svelte.d.ts +4 -0
  113. package/dist/components/primitives/Switch.svelte +53 -0
  114. package/dist/components/primitives/Switch.svelte.d.ts +4 -0
  115. package/dist/components/primitives/Tag.svelte +64 -0
  116. package/dist/components/primitives/Tag.svelte.d.ts +4 -0
  117. package/dist/components/primitives/Textarea.svelte +92 -0
  118. package/dist/components/primitives/Textarea.svelte.d.ts +4 -0
  119. package/dist/components/primitives/ToggleCheckbox.svelte +36 -0
  120. package/dist/components/primitives/ToggleCheckbox.svelte.d.ts +4 -0
  121. package/dist/components/primitives/ToggleInput.svelte +36 -0
  122. package/dist/components/primitives/ToggleInput.svelte.d.ts +4 -0
  123. package/dist/components/primitives/ToggleRadio.svelte +36 -0
  124. package/dist/components/primitives/ToggleRadio.svelte.d.ts +4 -0
  125. package/dist/components/primitives/index.d.ts +26 -0
  126. package/dist/components/primitives/index.js +30 -0
  127. package/dist/components/scenes/ai/AiDocumentDownloadMenu.svelte +387 -0
  128. package/dist/components/scenes/ai/AiDocumentDownloadMenu.svelte.d.ts +38 -0
  129. package/dist/components/scenes/ai/AiDocumentEditor.svelte +2259 -0
  130. package/dist/components/scenes/ai/AiDocumentEditor.svelte.d.ts +4 -0
  131. package/dist/components/scenes/ai/MarkdownRenderer.svelte +460 -0
  132. package/dist/components/scenes/ai/MarkdownRenderer.svelte.d.ts +4 -0
  133. package/dist/components/scenes/ai/document-download.d.ts +40 -0
  134. package/dist/components/scenes/ai/document-download.js +300 -0
  135. package/dist/components/scenes/ai/document-parse.d.ts +28 -0
  136. package/dist/components/scenes/ai/document-parse.js +243 -0
  137. package/dist/components/scenes/ai/document-types.d.ts +164 -0
  138. package/dist/components/scenes/ai/document-types.js +1 -0
  139. package/dist/components/scenes/ai/index.d.ts +17 -0
  140. package/dist/components/scenes/ai/index.js +13 -0
  141. package/dist/components/scenes/ai/markdown-parse.d.ts +32 -0
  142. package/dist/components/scenes/ai/markdown-parse.js +161 -0
  143. package/dist/components/scenes/app/FeedbackModal.svelte +160 -0
  144. package/dist/components/scenes/app/FeedbackModal.svelte.d.ts +47 -0
  145. package/dist/components/scenes/app/LanguageSwitch.svelte +136 -0
  146. package/dist/components/scenes/app/LanguageSwitch.svelte.d.ts +50 -0
  147. package/dist/components/scenes/app/SettingsModal.svelte +174 -0
  148. package/dist/components/scenes/app/SettingsModal.svelte.d.ts +31 -0
  149. package/dist/components/scenes/app/ThemeSelector.svelte +176 -0
  150. package/dist/components/scenes/app/ThemeSelector.svelte.d.ts +31 -0
  151. package/dist/components/scenes/app/ThemeToggle.svelte +76 -0
  152. package/dist/components/scenes/app/ThemeToggle.svelte.d.ts +29 -0
  153. package/dist/components/scenes/app/index.d.ts +11 -0
  154. package/dist/components/scenes/app/index.js +11 -0
  155. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte +39 -0
  156. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte.d.ts +18 -0
  157. package/dist/components/scenes/crud/CrudDetailDrawer.svelte +155 -0
  158. package/dist/components/scenes/crud/CrudDetailDrawer.svelte.d.ts +38 -0
  159. package/dist/components/scenes/crud/CrudEditDrawer.svelte +222 -0
  160. package/dist/components/scenes/crud/CrudEditDrawer.svelte.d.ts +48 -0
  161. package/dist/components/scenes/crud/CrudFilterBar.svelte +96 -0
  162. package/dist/components/scenes/crud/CrudFilterBar.svelte.d.ts +31 -0
  163. package/dist/components/scenes/crud/CrudPage.svelte +499 -0
  164. package/dist/components/scenes/crud/CrudPage.svelte.d.ts +114 -0
  165. package/dist/components/scenes/crud/crud-types.d.ts +135 -0
  166. package/dist/components/scenes/crud/crud-types.js +7 -0
  167. package/dist/components/scenes/crud/index.d.ts +12 -0
  168. package/dist/components/scenes/crud/index.js +11 -0
  169. package/dist/components/scenes/crypto/EncryptedInput.svelte +156 -0
  170. package/dist/components/scenes/crypto/EncryptedInput.svelte.d.ts +32 -0
  171. package/dist/components/scenes/crypto/HashDisplay.svelte +97 -0
  172. package/dist/components/scenes/crypto/HashDisplay.svelte.d.ts +4 -0
  173. package/dist/components/scenes/crypto/SignatureDisplay.svelte +161 -0
  174. package/dist/components/scenes/crypto/SignatureDisplay.svelte.d.ts +4 -0
  175. package/dist/components/scenes/crypto/index.d.ts +9 -0
  176. package/dist/components/scenes/crypto/index.js +11 -0
  177. package/dist/components/scenes/iam/ChangePasswordForm.svelte +134 -0
  178. package/dist/components/scenes/iam/ChangePasswordForm.svelte.d.ts +8 -0
  179. package/dist/components/scenes/iam/ForgotPasswordForm.svelte +147 -0
  180. package/dist/components/scenes/iam/ForgotPasswordForm.svelte.d.ts +4 -0
  181. package/dist/components/scenes/iam/LoginForm.svelte +191 -0
  182. package/dist/components/scenes/iam/LoginForm.svelte.d.ts +8 -0
  183. package/dist/components/scenes/iam/PasswordInput.svelte +203 -0
  184. package/dist/components/scenes/iam/PasswordInput.svelte.d.ts +49 -0
  185. package/dist/components/scenes/iam/PermGuard.svelte +69 -0
  186. package/dist/components/scenes/iam/PermGuard.svelte.d.ts +16 -0
  187. package/dist/components/scenes/iam/RegisterForm.svelte +269 -0
  188. package/dist/components/scenes/iam/RegisterForm.svelte.d.ts +8 -0
  189. package/dist/components/scenes/iam/ResetPasswordForm.svelte +153 -0
  190. package/dist/components/scenes/iam/ResetPasswordForm.svelte.d.ts +8 -0
  191. package/dist/components/scenes/iam/UserProfile.svelte +251 -0
  192. package/dist/components/scenes/iam/UserProfile.svelte.d.ts +4 -0
  193. package/dist/components/scenes/iam/index.d.ts +16 -0
  194. package/dist/components/scenes/iam/index.js +18 -0
  195. package/dist/components/scenes/iam/password-utils.d.ts +15 -0
  196. package/dist/components/scenes/iam/password-utils.js +19 -0
  197. package/dist/components/scenes/iam/permission-context.svelte.d.ts +90 -0
  198. package/dist/components/scenes/iam/permission-context.svelte.js +114 -0
  199. package/dist/components/scenes/index.d.ts +13 -0
  200. package/dist/components/scenes/index.js +20 -0
  201. package/dist/components/scenes/storage/AvatarUpload.svelte +218 -0
  202. package/dist/components/scenes/storage/AvatarUpload.svelte.d.ts +4 -0
  203. package/dist/components/scenes/storage/FileList.svelte +260 -0
  204. package/dist/components/scenes/storage/FileList.svelte.d.ts +4 -0
  205. package/dist/components/scenes/storage/FileUpload.svelte +400 -0
  206. package/dist/components/scenes/storage/FileUpload.svelte.d.ts +7 -0
  207. package/dist/components/scenes/storage/ImageUpload.svelte +285 -0
  208. package/dist/components/scenes/storage/ImageUpload.svelte.d.ts +4 -0
  209. package/dist/components/scenes/storage/index.d.ts +10 -0
  210. package/dist/components/scenes/storage/index.js +12 -0
  211. package/dist/components/scenes/types.d.ts +583 -0
  212. package/dist/components/scenes/types.js +7 -0
  213. package/dist/i18n.svelte.d.ts +44 -0
  214. package/dist/i18n.svelte.js +108 -0
  215. package/dist/index.d.ts +13 -0
  216. package/dist/index.js +19 -0
  217. package/dist/messages/en-US.json +242 -0
  218. package/dist/messages/zh-CN.json +242 -0
  219. package/dist/messages.d.ts +29 -0
  220. package/dist/messages.js +42 -0
  221. package/dist/styles/design-tokens.css +58 -0
  222. package/dist/styles/global.css +218 -0
  223. package/dist/styles/mobile.css +105 -0
  224. package/dist/theme-config.d.ts +92 -0
  225. package/dist/theme-config.js +122 -0
  226. package/dist/toast.svelte.d.ts +45 -0
  227. package/dist/toast.svelte.js +77 -0
  228. package/dist/types.d.ts +944 -0
  229. package/dist/types.js +7 -0
  230. package/dist/utils/platform.svelte.d.ts +54 -0
  231. package/dist/utils/platform.svelte.js +87 -0
  232. package/dist/utils.d.ts +46 -0
  233. package/dist/utils.js +100 -0
  234. package/package.json +69 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @h-ai/ui — CRUD 场景组件类型定义
3
+ *
4
+ * CrudPage 及其子组件的 Props 类型
5
+ * @module crud-types
6
+ */
7
+ import type { Snippet } from 'svelte';
8
+ import type { Size } from '../../../types.js';
9
+ /** CrudPage 权限控制 */
10
+ export interface CrudPermissions {
11
+ /** 允许新建 */
12
+ create?: boolean;
13
+ /** 允许编辑 */
14
+ update?: boolean;
15
+ /** 允许删除 */
16
+ delete?: boolean;
17
+ }
18
+ /** CrudPage 初始列表数据(由 +page.server.ts load 返回) */
19
+ export interface CrudPageData<T = Record<string, unknown>> {
20
+ items: T[];
21
+ total: number;
22
+ page: number;
23
+ pageSize: number;
24
+ filters?: Record<string, unknown>;
25
+ }
26
+ /** CrudPage 组件 Props */
27
+ export interface CrudPageProps<T = Record<string, unknown>> {
28
+ /** CRUD 操作定义(来自 kit.crud.define) */
29
+ crud: {
30
+ resource: {
31
+ name: string;
32
+ label: string | (() => string);
33
+ keyField?: string;
34
+ fields: Array<{
35
+ id: string;
36
+ label: string | (() => string);
37
+ type: string;
38
+ inList?: boolean;
39
+ filterable?: boolean;
40
+ readonly?: boolean;
41
+ inCreate?: boolean;
42
+ inEdit?: boolean;
43
+ inDetail?: boolean;
44
+ options?: Array<{
45
+ label: string;
46
+ value: string | number | boolean;
47
+ }> | (() => Array<{
48
+ label: string;
49
+ value: string | number | boolean;
50
+ }>);
51
+ validation?: {
52
+ required?: boolean;
53
+ min?: number;
54
+ max?: number;
55
+ pattern?: string;
56
+ message?: string;
57
+ };
58
+ width?: string;
59
+ align?: 'left' | 'center' | 'right';
60
+ render?: (value: unknown, item: Record<string, unknown>) => string;
61
+ placeholder?: string | (() => string);
62
+ defaultValue?: unknown;
63
+ order?: number;
64
+ }>;
65
+ defaultPageSize?: number;
66
+ searchable?: boolean;
67
+ searchPlaceholder?: string | (() => string);
68
+ api: {
69
+ list: (params: Record<string, unknown>) => Promise<{
70
+ items: T[];
71
+ total: number;
72
+ page: number;
73
+ pageSize: number;
74
+ }>;
75
+ get?: (id: string) => Promise<T | null>;
76
+ create?: (data: Partial<T>) => Promise<T>;
77
+ update?: (id: string, data: Partial<T>) => Promise<T>;
78
+ remove?: (id: string) => Promise<void>;
79
+ };
80
+ };
81
+ getListFields: () => Array<Record<string, unknown>>;
82
+ getFilterFields: () => Array<Record<string, unknown>>;
83
+ getCreateFields: () => Array<Record<string, unknown>>;
84
+ getEditFields: () => Array<Record<string, unknown>>;
85
+ getDetailFields: () => Array<Record<string, unknown>>;
86
+ toTableColumns: () => Array<{
87
+ key: string;
88
+ label: string;
89
+ width?: string;
90
+ align?: string;
91
+ render?: (item: Record<string, unknown>) => string;
92
+ }>;
93
+ getDefaultValues: () => Record<string, unknown>;
94
+ api: {
95
+ list: (params: Record<string, unknown>) => Promise<{
96
+ items: T[];
97
+ total: number;
98
+ page: number;
99
+ pageSize: number;
100
+ }>;
101
+ get?: (id: string) => Promise<T | null>;
102
+ create?: (data: Partial<T>) => Promise<T>;
103
+ update?: (id: string, data: Partial<T>) => Promise<T>;
104
+ remove?: (id: string) => Promise<void>;
105
+ };
106
+ };
107
+ /** 初始列表数据 */
108
+ data: CrudPageData<T>;
109
+ /** 权限控制 */
110
+ permissions?: CrudPermissions;
111
+ /** 抽屉尺寸(默认 '2xl') */
112
+ drawerSize?: Size;
113
+ /** 列表行点击是否打开详情(默认 true) */
114
+ rowClickDetail?: boolean;
115
+ /** 列表行操作按钮插槽 */
116
+ listItemActions?: Snippet<[T]>;
117
+ /** 编辑表单额外字段插槽 */
118
+ editFormExtra?: Snippet<[T | null, 'create' | 'edit']>;
119
+ /** 详情额外内容插槽 */
120
+ detailExtra?: Snippet<[T]>;
121
+ /** 页面头部额外操作区插槽 */
122
+ headerActions?: Snippet;
123
+ /** 删除前钩子(返回 false 取消) */
124
+ onbeforedelete?: (item: T) => Promise<boolean> | boolean;
125
+ /** 提交成功后钩子 */
126
+ onaftersubmit?: (item: T, mode: 'create' | 'edit') => void;
127
+ /** 删除成功后钩子 */
128
+ onafterdelete?: (item: T) => void;
129
+ /** 自定义错误处理 */
130
+ onerror?: (error: string) => void;
131
+ /** 自定义类名 */
132
+ class?: string;
133
+ /** 当前路由路径(用于 URL 参数同步) */
134
+ basePath?: string;
135
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @h-ai/ui — CRUD 场景组件类型定义
3
+ *
4
+ * CrudPage 及其子组件的 Props 类型
5
+ * @module crud-types
6
+ */
7
+ export {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @h-ai/ui — CRUD 场景组件
3
+ *
4
+ * 提供声明式 CRUD 页面组件,基于 kit.crud.define() 定义自动渲染列表、搜索过滤、分页、详情/编辑抽屉和删除确认。
5
+ * @module crud
6
+ */
7
+ export type * from './crud-types.js';
8
+ export { default as CrudDeleteConfirm } from './CrudDeleteConfirm.svelte';
9
+ export { default as CrudDetailDrawer } from './CrudDetailDrawer.svelte';
10
+ export { default as CrudEditDrawer } from './CrudEditDrawer.svelte';
11
+ export { default as CrudFilterBar } from './CrudFilterBar.svelte';
12
+ export { default as CrudPage } from './CrudPage.svelte';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @h-ai/ui — CRUD 场景组件
3
+ *
4
+ * 提供声明式 CRUD 页面组件,基于 kit.crud.define() 定义自动渲染列表、搜索过滤、分页、详情/编辑抽屉和删除确认。
5
+ * @module crud
6
+ */
7
+ export { default as CrudDeleteConfirm } from './CrudDeleteConfirm.svelte';
8
+ export { default as CrudDetailDrawer } from './CrudDetailDrawer.svelte';
9
+ export { default as CrudEditDrawer } from './CrudEditDrawer.svelte';
10
+ export { default as CrudFilterBar } from './CrudFilterBar.svelte';
11
+ export { default as CrudPage } from './CrudPage.svelte';
@@ -0,0 +1,156 @@
1
+ <!--
2
+ =============================================================================
3
+ @h-ai/ui - EncryptedInput 组件
4
+ =============================================================================
5
+ 加密输入框组件,支持自动加密显示
6
+
7
+ 使用 Svelte 5 Runes ($props, $state, $derived, $bindable)
8
+ 内置多语言支持,自动跟随全局 locale
9
+ =============================================================================
10
+ -->
11
+ <script lang='ts'>
12
+ import type { Size } from '../../../types.js'
13
+ import { uiM } from '../../../messages.js'
14
+ import BareButton from '../../primitives/BareButton.svelte'
15
+ import IconButton from '../../primitives/IconButton.svelte'
16
+ import Input from '../../primitives/Input.svelte'
17
+
18
+ interface Props {
19
+ /** 原始值 */
20
+ value?: string
21
+ /** 加密后的值 */
22
+ encryptedValue?: string
23
+ /** 占位符 */
24
+ placeholder?: string
25
+ /** 尺寸 */
26
+ size?: Size
27
+ /** 是否禁用 */
28
+ disabled?: boolean
29
+ /** 是否显示加密结果 */
30
+ showEncrypted?: boolean
31
+ /** 加密算法 */
32
+ algorithm?: string
33
+ /** 自定义类名 */
34
+ class?: string
35
+ /** 加密函数 */
36
+ onencrypt?: (value: string) => Promise<string>
37
+ /** 输入事件 */
38
+ oninput?: (e: Event & { currentTarget: HTMLInputElement }) => void
39
+ /** 变化事件 */
40
+ onchange?: (e: Event & { currentTarget: HTMLInputElement }) => void
41
+ }
42
+
43
+ let {
44
+ value = $bindable(''),
45
+ encryptedValue = $bindable(''),
46
+ placeholder,
47
+ size = 'md',
48
+ disabled = false,
49
+ showEncrypted = false,
50
+ algorithm = 'SM4',
51
+ class: className = '',
52
+ onencrypt,
53
+ oninput,
54
+ onchange,
55
+ }: Props = $props()
56
+
57
+ let showValue = $state(false)
58
+
59
+ // 模拟加密(实际应该调用 crypto 服务)
60
+ function encrypt(text: string): string {
61
+ return btoa(text)
62
+ }
63
+
64
+ function handleInput(e: Event & { currentTarget: HTMLInputElement }) {
65
+ value = e.currentTarget.value
66
+
67
+ if (value && onencrypt) {
68
+ onencrypt(value).then((encrypted) => {
69
+ encryptedValue = encrypted
70
+ })
71
+ }
72
+ else if (value) {
73
+ encryptedValue = encrypt(value)
74
+ }
75
+ else {
76
+ encryptedValue = ''
77
+ }
78
+
79
+ oninput?.(e)
80
+ }
81
+
82
+ function handleChange(e: Event & { currentTarget: HTMLInputElement }) {
83
+ onchange?.(e)
84
+ }
85
+
86
+ function toggleShow() {
87
+ showValue = !showValue
88
+ }
89
+
90
+ function copyEncrypted() {
91
+ if (encryptedValue) {
92
+ navigator.clipboard.writeText(encryptedValue)
93
+ }
94
+ }
95
+ </script>
96
+
97
+ <div class='encrypted-input space-y-2 {className}'>
98
+ <!-- 输入框 -->
99
+ <div class='relative'>
100
+ <Input
101
+ type={showValue ? 'text' : 'password'}
102
+ placeholder={placeholder || uiM('encrypted_input_placeholder')}
103
+ {disabled}
104
+ {size}
105
+ bind:value
106
+ oninput={handleInput}
107
+ onchange={handleChange}
108
+ class='pr-10'
109
+ />
110
+
111
+ <BareButton
112
+ type='button'
113
+ class='absolute right-3 top-1/2 -translate-y-1/2 text-base-content/50 hover:text-base-content'
114
+ onclick={toggleShow}
115
+ tabindex={-1}
116
+ ariaLabel={showValue ? uiM('encrypted_input_hide') : uiM('encrypted_input_show')}
117
+ >
118
+ {#if showValue}
119
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-5 w-5' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
120
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21' />
121
+ </svg>
122
+ {:else}
123
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-5 w-5' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
124
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 12a3 3 0 11-6 0 3 3 0 016 0z' />
125
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z' />
126
+ </svg>
127
+ {/if}
128
+ </BareButton>
129
+ </div>
130
+
131
+ <!-- 加密结果展示 -->
132
+ {#if showEncrypted && encryptedValue}
133
+ <div class='bg-base-200 rounded-lg p-3'>
134
+ <div class='flex items-center justify-between mb-1'>
135
+ <span class='text-xs text-base-content/60'>
136
+ {uiM('encrypted_input_result')} ({algorithm})
137
+ </span>
138
+ <IconButton
139
+ size='xs'
140
+ variant='ghost'
141
+ label={uiM('encrypted_input_copy')}
142
+ onclick={copyEncrypted}
143
+ >
144
+ {#snippet children()}
145
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
146
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z' />
147
+ </svg>
148
+ {/snippet}
149
+ </IconButton>
150
+ </div>
151
+ <code class='text-xs break-all text-base-content/80'>
152
+ {encryptedValue}
153
+ </code>
154
+ </div>
155
+ {/if}
156
+ </div>
@@ -0,0 +1,32 @@
1
+ import type { Size } from '../../../types.js';
2
+ interface Props {
3
+ /** 原始值 */
4
+ value?: string;
5
+ /** 加密后的值 */
6
+ encryptedValue?: string;
7
+ /** 占位符 */
8
+ placeholder?: string;
9
+ /** 尺寸 */
10
+ size?: Size;
11
+ /** 是否禁用 */
12
+ disabled?: boolean;
13
+ /** 是否显示加密结果 */
14
+ showEncrypted?: boolean;
15
+ /** 加密算法 */
16
+ algorithm?: string;
17
+ /** 自定义类名 */
18
+ class?: string;
19
+ /** 加密函数 */
20
+ onencrypt?: (value: string) => Promise<string>;
21
+ /** 输入事件 */
22
+ oninput?: (e: Event & {
23
+ currentTarget: HTMLInputElement;
24
+ }) => void;
25
+ /** 变化事件 */
26
+ onchange?: (e: Event & {
27
+ currentTarget: HTMLInputElement;
28
+ }) => void;
29
+ }
30
+ declare const EncryptedInput: import("svelte").Component<Props, {}, "value" | "encryptedValue">;
31
+ type EncryptedInput = ReturnType<typeof EncryptedInput>;
32
+ export default EncryptedInput;
@@ -0,0 +1,97 @@
1
+ <!--
2
+ =============================================================================
3
+ @h-ai/ui - HashDisplay 组件
4
+ =============================================================================
5
+ 哈希值展示组件
6
+
7
+ 使用 Svelte 5 Runes ($props, $state, $derived)
8
+ 使用 primitives 组件:IconButton, Badge
9
+ =============================================================================
10
+ -->
11
+ <script lang='ts'>
12
+ import type { HashDisplayProps } from '../types.js'
13
+ import { uiM } from '../../../messages.js'
14
+ import { cn } from '../../../utils.js'
15
+ import Badge from '../../primitives/Badge.svelte'
16
+ import IconButton from '../../primitives/IconButton.svelte'
17
+
18
+ const {
19
+ value = '',
20
+ algorithm = 'SM3',
21
+ label = '',
22
+ copyable = true,
23
+ truncate = true,
24
+ truncateLength = 16,
25
+ labels = {},
26
+ class: className = '',
27
+ }: HashDisplayProps = $props()
28
+
29
+ let copied = $state(false)
30
+
31
+ const containerClass = $derived(
32
+ cn(
33
+ 'hash-display',
34
+ className,
35
+ ),
36
+ )
37
+
38
+ const displayValue = $derived(
39
+ truncate && value.length > truncateLength * 2
40
+ ? `${value.slice(0, truncateLength)}...${value.slice(-truncateLength)}`
41
+ : value,
42
+ )
43
+
44
+ async function copyToClipboard() {
45
+ if (!value)
46
+ return
47
+
48
+ try {
49
+ await navigator.clipboard.writeText(value)
50
+ copied = true
51
+ setTimeout(() => {
52
+ copied = false
53
+ }, 2000)
54
+ }
55
+ catch {
56
+ // 复制失败
57
+ }
58
+ }
59
+ </script>
60
+
61
+ <div class={containerClass}>
62
+ {#if label}
63
+ <div class='text-xs text-base-content/60 mb-1'>
64
+ {label}
65
+ {#if algorithm}
66
+ <Badge size='xs' variant='ghost' class='ml-1'>{algorithm}</Badge>
67
+ {/if}
68
+ </div>
69
+ {/if}
70
+
71
+ <div class='flex items-center gap-2 bg-base-200 rounded-lg px-3 py-2'>
72
+ <code class='flex-1 text-sm font-mono break-all text-base-content/80' title={value}>
73
+ {displayValue || '-'}
74
+ </code>
75
+
76
+ {#if copyable && value}
77
+ <IconButton
78
+ size='xs'
79
+ variant='ghost'
80
+ label={labels.copyHash ?? uiM('hash_copy')}
81
+ onclick={copyToClipboard}
82
+ >
83
+ {#snippet children()}
84
+ {#if copied}
85
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4 text-success' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
86
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 13l4 4L19 7' />
87
+ </svg>
88
+ {:else}
89
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
90
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z' />
91
+ </svg>
92
+ {/if}
93
+ {/snippet}
94
+ </IconButton>
95
+ {/if}
96
+ </div>
97
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { HashDisplayProps } from '../types.js';
2
+ declare const HashDisplay: import("svelte").Component<HashDisplayProps, {}, "">;
3
+ type HashDisplay = ReturnType<typeof HashDisplay>;
4
+ export default HashDisplay;
@@ -0,0 +1,161 @@
1
+ <!--
2
+ =============================================================================
3
+ @h-ai/ui - SignatureDisplay 组件
4
+ =============================================================================
5
+ 签名信息展示组件
6
+
7
+ 使用 Svelte 5 Runes ($props, $state, $derived)
8
+ 使用 primitives 组件:IconButton, Badge
9
+ =============================================================================
10
+ -->
11
+ <script lang='ts'>
12
+ import type { SignatureDisplayProps } from '../types.js'
13
+ import { uiM } from '../../../messages.js'
14
+ import { cn } from '../../../utils.js'
15
+ import Badge from '../../primitives/Badge.svelte'
16
+
17
+ import IconButton from '../../primitives/IconButton.svelte'
18
+
19
+ const {
20
+ signature = '',
21
+ publicKey = '',
22
+ algorithm = 'SM2',
23
+ verified = undefined,
24
+ showPublicKey = false,
25
+ copyable = true,
26
+ labels = {},
27
+ class: className = '',
28
+ }: SignatureDisplayProps = $props()
29
+
30
+ let copiedSig = $state(false)
31
+ let copiedKey = $state(false)
32
+
33
+ const containerClass = $derived(
34
+ cn(
35
+ 'signature-display space-y-3',
36
+ className,
37
+ ),
38
+ )
39
+
40
+ const verifyStatusText = $derived(
41
+ verified === true
42
+ ? (labels.verified ?? uiM('signature_verified'))
43
+ : verified === false
44
+ ? (labels.verifyFailed ?? uiM('signature_verify_failed'))
45
+ : (labels.notVerified ?? uiM('signature_not_verified')),
46
+ )
47
+
48
+ async function copySignature() {
49
+ if (!signature)
50
+ return
51
+ try {
52
+ await navigator.clipboard.writeText(signature)
53
+ copiedSig = true
54
+ setTimeout(() => {
55
+ copiedSig = false
56
+ }, 2000)
57
+ }
58
+ catch {
59
+ // 复制失败
60
+ }
61
+ }
62
+
63
+ async function copyPublicKey() {
64
+ if (!publicKey)
65
+ return
66
+ try {
67
+ await navigator.clipboard.writeText(publicKey)
68
+ copiedKey = true
69
+ setTimeout(() => {
70
+ copiedKey = false
71
+ }, 2000)
72
+ }
73
+ catch {
74
+ // 复制失败
75
+ }
76
+ }
77
+ </script>
78
+
79
+ <div class={containerClass}>
80
+ <!-- 签名状态 -->
81
+ <div class='flex items-center gap-2'>
82
+ <span class='text-sm font-medium'>{labels.signature ?? uiM('signature_label')} ({algorithm})</span>
83
+ {#if verified !== undefined}
84
+ <Badge size='sm' variant={verified ? 'success' : 'error'}>
85
+ {#if verified}
86
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-3 w-3 mr-1' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
87
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 13l4 4L19 7' />
88
+ </svg>
89
+ {:else}
90
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-3 w-3 mr-1' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
91
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12' />
92
+ </svg>
93
+ {/if}
94
+ {verifyStatusText}
95
+ </Badge>
96
+ {/if}
97
+ </div>
98
+
99
+ <!-- 签名值 -->
100
+ <div class='bg-base-200 rounded-lg p-3'>
101
+ <div class='flex items-start justify-between gap-2'>
102
+ <code class='text-xs font-mono break-all text-base-content/80 flex-1'>
103
+ {signature || (labels.noSignature ?? uiM('signature_no_signature'))}
104
+ </code>
105
+ {#if copyable && signature}
106
+ <IconButton
107
+ size='xs'
108
+ variant='ghost'
109
+ label={labels.copySignature ?? uiM('signature_copy_signature')}
110
+ onclick={copySignature}
111
+ >
112
+ {#snippet children()}
113
+ {#if copiedSig}
114
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4 text-success' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
115
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 13l4 4L19 7' />
116
+ </svg>
117
+ {:else}
118
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
119
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z' />
120
+ </svg>
121
+ {/if}
122
+ {/snippet}
123
+ </IconButton>
124
+ {/if}
125
+ </div>
126
+ </div>
127
+
128
+ <!-- 公钥(可选) -->
129
+ {#if showPublicKey && publicKey}
130
+ <div>
131
+ <div class='text-xs text-base-content/60 mb-1'>{labels.publicKey ?? uiM('signature_public_key')}</div>
132
+ <div class='bg-base-200 rounded-lg p-3'>
133
+ <div class='flex items-start justify-between gap-2'>
134
+ <code class='text-xs font-mono break-all text-base-content/80 flex-1'>
135
+ {publicKey}
136
+ </code>
137
+ {#if copyable}
138
+ <IconButton
139
+ size='xs'
140
+ variant='ghost'
141
+ label={labels.copyPublicKey ?? uiM('signature_copy_public_key')}
142
+ onclick={copyPublicKey}
143
+ >
144
+ {#snippet children()}
145
+ {#if copiedKey}
146
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4 text-success' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
147
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 13l4 4L19 7' />
148
+ </svg>
149
+ {:else}
150
+ <svg xmlns='http://www.w3.org/2000/svg' class='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
151
+ <path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z' />
152
+ </svg>
153
+ {/if}
154
+ {/snippet}
155
+ </IconButton>
156
+ {/if}
157
+ </div>
158
+ </div>
159
+ </div>
160
+ {/if}
161
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { SignatureDisplayProps } from '../types.js';
2
+ declare const SignatureDisplay: import("svelte").Component<SignatureDisplayProps, {}, "">;
3
+ type SignatureDisplay = ReturnType<typeof SignatureDisplay>;
4
+ export default SignatureDisplay;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @h-ai/ui — Crypto 场景组件导出
3
+ *
4
+ * 加密相关的场景化组件
5
+ * @module index
6
+ */
7
+ export { default as EncryptedInput } from './EncryptedInput.svelte';
8
+ export { default as HashDisplay } from './HashDisplay.svelte';
9
+ export { default as SignatureDisplay } from './SignatureDisplay.svelte';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @h-ai/ui — Crypto 场景组件导出
3
+ *
4
+ * 加密相关的场景化组件
5
+ * @module index
6
+ */
7
+ // 输入组件
8
+ export { default as EncryptedInput } from './EncryptedInput.svelte';
9
+ // 展示组件
10
+ export { default as HashDisplay } from './HashDisplay.svelte';
11
+ export { default as SignatureDisplay } from './SignatureDisplay.svelte';