@h-ai/ui 0.1.0-alpha.10

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 (237) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +500 -0
  3. package/auto-import.d.ts +96 -0
  4. package/auto-import.js +263 -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 +104 -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 +2209 -0
  130. package/dist/components/scenes/ai/AiDocumentEditor.svelte.d.ts +4 -0
  131. package/dist/components/scenes/ai/MarkdownRenderer.svelte +412 -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/highlight.d.ts +26 -0
  140. package/dist/components/scenes/ai/highlight.js +151 -0
  141. package/dist/components/scenes/ai/index.d.ts +17 -0
  142. package/dist/components/scenes/ai/index.js +13 -0
  143. package/dist/components/scenes/ai/markdown-parse.d.ts +32 -0
  144. package/dist/components/scenes/ai/markdown-parse.js +164 -0
  145. package/dist/components/scenes/app/FeedbackModal.svelte +160 -0
  146. package/dist/components/scenes/app/FeedbackModal.svelte.d.ts +47 -0
  147. package/dist/components/scenes/app/LanguageSwitch.svelte +136 -0
  148. package/dist/components/scenes/app/LanguageSwitch.svelte.d.ts +50 -0
  149. package/dist/components/scenes/app/SettingsModal.svelte +174 -0
  150. package/dist/components/scenes/app/SettingsModal.svelte.d.ts +31 -0
  151. package/dist/components/scenes/app/ThemeSelector.svelte +176 -0
  152. package/dist/components/scenes/app/ThemeSelector.svelte.d.ts +31 -0
  153. package/dist/components/scenes/app/ThemeToggle.svelte +76 -0
  154. package/dist/components/scenes/app/ThemeToggle.svelte.d.ts +29 -0
  155. package/dist/components/scenes/app/index.d.ts +11 -0
  156. package/dist/components/scenes/app/index.js +11 -0
  157. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte +39 -0
  158. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte.d.ts +18 -0
  159. package/dist/components/scenes/crud/CrudDetailDrawer.svelte +155 -0
  160. package/dist/components/scenes/crud/CrudDetailDrawer.svelte.d.ts +38 -0
  161. package/dist/components/scenes/crud/CrudEditDrawer.svelte +225 -0
  162. package/dist/components/scenes/crud/CrudEditDrawer.svelte.d.ts +48 -0
  163. package/dist/components/scenes/crud/CrudFilterBar.svelte +96 -0
  164. package/dist/components/scenes/crud/CrudFilterBar.svelte.d.ts +31 -0
  165. package/dist/components/scenes/crud/CrudPage.svelte +499 -0
  166. package/dist/components/scenes/crud/CrudPage.svelte.d.ts +114 -0
  167. package/dist/components/scenes/crud/crud-types.d.ts +135 -0
  168. package/dist/components/scenes/crud/crud-types.js +7 -0
  169. package/dist/components/scenes/crud/index.d.ts +12 -0
  170. package/dist/components/scenes/crud/index.js +11 -0
  171. package/dist/components/scenes/crypto/EncryptedInput.svelte +156 -0
  172. package/dist/components/scenes/crypto/EncryptedInput.svelte.d.ts +32 -0
  173. package/dist/components/scenes/crypto/HashDisplay.svelte +97 -0
  174. package/dist/components/scenes/crypto/HashDisplay.svelte.d.ts +4 -0
  175. package/dist/components/scenes/crypto/SignatureDisplay.svelte +161 -0
  176. package/dist/components/scenes/crypto/SignatureDisplay.svelte.d.ts +4 -0
  177. package/dist/components/scenes/crypto/index.d.ts +9 -0
  178. package/dist/components/scenes/crypto/index.js +11 -0
  179. package/dist/components/scenes/iam/ChangePasswordForm.svelte +134 -0
  180. package/dist/components/scenes/iam/ChangePasswordForm.svelte.d.ts +8 -0
  181. package/dist/components/scenes/iam/ForgotPasswordForm.svelte +147 -0
  182. package/dist/components/scenes/iam/ForgotPasswordForm.svelte.d.ts +4 -0
  183. package/dist/components/scenes/iam/LoginForm.svelte +191 -0
  184. package/dist/components/scenes/iam/LoginForm.svelte.d.ts +8 -0
  185. package/dist/components/scenes/iam/PasswordInput.svelte +208 -0
  186. package/dist/components/scenes/iam/PasswordInput.svelte.d.ts +49 -0
  187. package/dist/components/scenes/iam/PermGuard.svelte +69 -0
  188. package/dist/components/scenes/iam/PermGuard.svelte.d.ts +16 -0
  189. package/dist/components/scenes/iam/RegisterForm.svelte +269 -0
  190. package/dist/components/scenes/iam/RegisterForm.svelte.d.ts +8 -0
  191. package/dist/components/scenes/iam/ResetPasswordForm.svelte +153 -0
  192. package/dist/components/scenes/iam/ResetPasswordForm.svelte.d.ts +8 -0
  193. package/dist/components/scenes/iam/UserProfile.svelte +251 -0
  194. package/dist/components/scenes/iam/UserProfile.svelte.d.ts +4 -0
  195. package/dist/components/scenes/iam/index.d.ts +16 -0
  196. package/dist/components/scenes/iam/index.js +18 -0
  197. package/dist/components/scenes/iam/password-utils.d.ts +15 -0
  198. package/dist/components/scenes/iam/password-utils.js +19 -0
  199. package/dist/components/scenes/iam/permission-context.svelte.d.ts +90 -0
  200. package/dist/components/scenes/iam/permission-context.svelte.js +114 -0
  201. package/dist/components/scenes/index.d.ts +13 -0
  202. package/dist/components/scenes/index.js +20 -0
  203. package/dist/components/scenes/storage/AvatarUpload.svelte +218 -0
  204. package/dist/components/scenes/storage/AvatarUpload.svelte.d.ts +4 -0
  205. package/dist/components/scenes/storage/FileList.svelte +260 -0
  206. package/dist/components/scenes/storage/FileList.svelte.d.ts +4 -0
  207. package/dist/components/scenes/storage/FileUpload.svelte +402 -0
  208. package/dist/components/scenes/storage/FileUpload.svelte.d.ts +7 -0
  209. package/dist/components/scenes/storage/ImageUpload.svelte +287 -0
  210. package/dist/components/scenes/storage/ImageUpload.svelte.d.ts +4 -0
  211. package/dist/components/scenes/storage/index.d.ts +10 -0
  212. package/dist/components/scenes/storage/index.js +12 -0
  213. package/dist/components/scenes/types.d.ts +583 -0
  214. package/dist/components/scenes/types.js +7 -0
  215. package/dist/i18n.svelte.d.ts +44 -0
  216. package/dist/i18n.svelte.js +108 -0
  217. package/dist/index.d.ts +13 -0
  218. package/dist/index.js +19 -0
  219. package/dist/messages/en-US.json +242 -0
  220. package/dist/messages/zh-CN.json +242 -0
  221. package/dist/messages.d.ts +29 -0
  222. package/dist/messages.js +42 -0
  223. package/dist/styles/design-tokens.css +58 -0
  224. package/dist/styles/global.css +258 -0
  225. package/dist/styles/mobile.css +105 -0
  226. package/dist/styles/theme.css +31 -0
  227. package/dist/theme-config.d.ts +92 -0
  228. package/dist/theme-config.js +122 -0
  229. package/dist/toast.svelte.d.ts +45 -0
  230. package/dist/toast.svelte.js +77 -0
  231. package/dist/types.d.ts +944 -0
  232. package/dist/types.js +7 -0
  233. package/dist/utils/platform.svelte.d.ts +54 -0
  234. package/dist/utils/platform.svelte.js +89 -0
  235. package/dist/utils.d.ts +46 -0
  236. package/dist/utils.js +163 -0
  237. package/package.json +70 -0
package/auto-import.js ADDED
@@ -0,0 +1,263 @@
1
+ /**
2
+ * =============================================================================
3
+ * @h-ai/ui - 自动导入预处理器
4
+ * =============================================================================
5
+ * 目标:在 Svelte 编译阶段自动注入 @h-ai/ui 组件 import,避免页面显式引入。
6
+ * 说明:该预处理器会在 svelte-check 与 Vite 编译时生效。
7
+ * =============================================================================
8
+ */
9
+
10
+ const UI_COMPONENTS = new Set([
11
+ // primitives
12
+ 'Avatar',
13
+ 'Badge',
14
+ 'BareButton',
15
+ 'BareInput',
16
+ 'Button',
17
+ 'Checkbox',
18
+ 'IconButton',
19
+ 'Input',
20
+ 'Progress',
21
+ 'Radio',
22
+ 'Range',
23
+ 'Rating',
24
+ 'Select',
25
+ 'Spinner',
26
+ 'Switch',
27
+ 'Tag',
28
+ 'Textarea',
29
+ 'ToggleCheckbox',
30
+ 'ToggleInput',
31
+ 'ToggleRadio',
32
+ // compounds
33
+ 'Accordion',
34
+ 'ActionSheet',
35
+ 'Alert',
36
+ 'AppBar',
37
+ 'BottomNav',
38
+ 'Breadcrumb',
39
+ 'Calendar',
40
+ 'Card',
41
+ 'Combobox',
42
+ 'Confirm',
43
+ 'DataTable',
44
+ 'DatePicker',
45
+ 'Drawer',
46
+ 'Dropdown',
47
+ 'Empty',
48
+ 'Form',
49
+ 'FormField',
50
+ 'InfiniteScroll',
51
+ 'Modal',
52
+ 'PageHeader',
53
+ 'Pagination',
54
+ 'Popover',
55
+ 'PullRefresh',
56
+ 'Result',
57
+ 'SafeArea',
58
+ 'Skeleton',
59
+ 'Steps',
60
+ 'SwipeCell',
61
+ 'Tabs',
62
+ 'TagInput',
63
+ 'Timeline',
64
+ 'ToastContainer',
65
+ 'Tooltip',
66
+ // scenes - app
67
+ 'FeedbackModal',
68
+ 'LanguageSwitch',
69
+ 'SettingsModal',
70
+ 'ThemeSelector',
71
+ 'ThemeToggle',
72
+ // scenes - iam
73
+ 'ChangePasswordForm',
74
+ 'ForgotPasswordForm',
75
+ 'LoginForm',
76
+ 'PasswordInput',
77
+ 'PermGuard',
78
+ 'RegisterForm',
79
+ 'ResetPasswordForm',
80
+ 'UserProfile',
81
+ // scenes - storage
82
+ 'AvatarUpload',
83
+ 'FileList',
84
+ 'FileUpload',
85
+ 'ImageUpload',
86
+ // scenes - crypto
87
+ 'EncryptedInput',
88
+ 'HashDisplay',
89
+ 'SignatureDisplay',
90
+ // scenes - ai
91
+ 'AiDocumentEditor',
92
+ 'MarkdownRenderer',
93
+ ])
94
+
95
+ const TAG_REGEX = /<([A-Z][A-Za-z0-9]*)\b/g
96
+ const SCRIPT_REGEX = /<script\b([^>]*)>([\s\S]*?)<\/script>/g
97
+ const UI_IMPORT_REGEX = /import\s*\{([^}]+)\}\s*from\s*['"]@h-ai\/ui['"];?/
98
+ const IMPORT_ALIAS_SPLIT_REGEX = /\s+as\s+/i
99
+ const WINDOWS_PATH_SEPARATOR_REGEX = /\\/g
100
+ const MODULE_CONTEXT_ATTR_REGEX = /context\s*=\s*['"]module['"]/i
101
+ const TYPE_IMPORT_PREFIX_REGEX = /^type\s+/
102
+
103
+ function collectUsedComponents(content) {
104
+ const used = new Set()
105
+ for (const match of content.matchAll(TAG_REGEX)) {
106
+ const name = match[1]
107
+ if (UI_COMPONENTS.has(name)) {
108
+ used.add(name)
109
+ }
110
+ }
111
+ return used
112
+ }
113
+
114
+ function collectImportedNames(scriptContent) {
115
+ const imported = new Set()
116
+ const lines = scriptContent.split('\n')
117
+ let buffer = ''
118
+
119
+ const flushImport = (statement) => {
120
+ const fromIndex = statement.lastIndexOf(' from ')
121
+ if (fromIndex === -1)
122
+ return
123
+
124
+ let clause = statement.slice('import '.length, fromIndex).trim()
125
+ clause = clause.replace(TYPE_IMPORT_PREFIX_REGEX, '')
126
+ if (!clause)
127
+ return
128
+
129
+ // default + named: Button, { Input as UiInput }
130
+ if (clause.includes('{')) {
131
+ const [defaultPart, namedPart] = clause.split('{')
132
+ const defaultName = defaultPart.replace(',', '').trim()
133
+ if (defaultName)
134
+ imported.add(defaultName)
135
+
136
+ const raw = namedPart.replace('}', '')
137
+ for (const segment of raw.split(',')) {
138
+ const cleaned = segment.trim().replace(TYPE_IMPORT_PREFIX_REGEX, '')
139
+ if (!cleaned)
140
+ continue
141
+ const [original] = cleaned.split(IMPORT_ALIAS_SPLIT_REGEX)
142
+ if (original)
143
+ imported.add(original.trim())
144
+ }
145
+ return
146
+ }
147
+
148
+ // namespace import: * as name
149
+ if (clause.startsWith('* as ')) {
150
+ const name = clause.replace('* as ', '').trim()
151
+ if (name)
152
+ imported.add(name)
153
+ return
154
+ }
155
+
156
+ // default import
157
+ imported.add(clause)
158
+ }
159
+
160
+ for (const line of lines) {
161
+ const trimmed = line.trim()
162
+ if (!buffer) {
163
+ if (!trimmed.startsWith('import '))
164
+ continue
165
+ buffer = trimmed
166
+ if (trimmed.endsWith(';')) {
167
+ flushImport(buffer)
168
+ buffer = ''
169
+ }
170
+ continue
171
+ }
172
+
173
+ buffer += ` ${trimmed}`
174
+ if (trimmed.endsWith(';')) {
175
+ flushImport(buffer)
176
+ buffer = ''
177
+ }
178
+ }
179
+
180
+ if (buffer)
181
+ flushImport(buffer)
182
+
183
+ return imported
184
+ }
185
+
186
+ function mergeHaiUiImport(scriptContent, components) {
187
+ if (components.length === 0)
188
+ return scriptContent
189
+
190
+ const existingMatch = scriptContent.match(UI_IMPORT_REGEX)
191
+ if (existingMatch) {
192
+ const existing = existingMatch[1]
193
+ .split(',')
194
+ .map(name => name.trim())
195
+ .filter(Boolean)
196
+
197
+ const merged = [...existing, ...components.filter(name => !existing.includes(name))]
198
+ const updated = `import { ${merged.join(', ')} } from '@h-ai/ui'`
199
+ return scriptContent.replace(UI_IMPORT_REGEX, updated)
200
+ }
201
+
202
+ return `import { ${components.join(', ')} } from '@h-ai/ui'\n${scriptContent}`
203
+ }
204
+
205
+ function updateScriptBlock(scriptContent, usedComponents) {
206
+ const imported = collectImportedNames(scriptContent)
207
+ const missing = [...usedComponents].filter(name => !imported.has(name))
208
+ return mergeHaiUiImport(scriptContent, missing)
209
+ }
210
+
211
+ function autoImportHaiUi() {
212
+ return {
213
+ name: 'auto-import-hai-ui',
214
+ markup({ content, filename }) {
215
+ if (!filename || !filename.endsWith('.svelte')) {
216
+ return { code: content }
217
+ }
218
+
219
+ // 跳过 @h-ai/ui 包自身的文件,避免重复导入
220
+ const normalizedPath = filename.replace(WINDOWS_PATH_SEPARATOR_REGEX, '/')
221
+ if (normalizedPath.includes('/packages/ui/') || normalizedPath.includes('/@h-ai/ui/')) {
222
+ return { code: content }
223
+ }
224
+
225
+ const usedComponents = collectUsedComponents(content)
226
+ if (usedComponents.size === 0) {
227
+ return { code: content }
228
+ }
229
+
230
+ let lastIndex = 0
231
+ let updated = ''
232
+ let applied = false
233
+
234
+ for (const match of content.matchAll(SCRIPT_REGEX)) {
235
+ const [fullMatch, attrs, scriptContent] = match
236
+ const isModule = MODULE_CONTEXT_ATTR_REGEX.test(attrs)
237
+ const start = match.index ?? 0
238
+
239
+ updated += content.slice(lastIndex, start)
240
+ lastIndex = start + fullMatch.length
241
+
242
+ if (!applied && !isModule) {
243
+ const newScript = updateScriptBlock(scriptContent, usedComponents)
244
+ updated += `<script${attrs}>${newScript}</script>`
245
+ applied = true
246
+ }
247
+ else {
248
+ updated += fullMatch
249
+ }
250
+ }
251
+
252
+ if (!applied) {
253
+ const scriptBlock = `<script lang="ts">${updateScriptBlock('', usedComponents)}</script>\n`
254
+ return { code: scriptBlock + content }
255
+ }
256
+
257
+ updated += content.slice(lastIndex)
258
+ return { code: updated }
259
+ },
260
+ }
261
+ }
262
+
263
+ export { autoImportHaiUi }
@@ -0,0 +1,142 @@
1
+ <!--
2
+ =============================================================================
3
+ @h-ai/ui - Accordion 组件
4
+ =============================================================================
5
+ 手风琴/折叠面板组件,支持单选/多选模式、多种样式变体
6
+
7
+ 使用 Svelte 5 Runes ($props, $state, $derived)
8
+ 使用 DaisyUI collapse 类
9
+ =============================================================================
10
+ -->
11
+
12
+ <script lang='ts'>
13
+ import type { Snippet } from 'svelte'
14
+ import type { AccordionItem } from './accordion-types.js'
15
+ import { cn } from '../../utils.js'
16
+ import ToggleCheckbox from '../primitives/ToggleCheckbox.svelte'
17
+ import ToggleRadio from '../primitives/ToggleRadio.svelte'
18
+
19
+ interface Props {
20
+ /** 折叠项数据 */
21
+ items: AccordionItem[]
22
+ /** 当前展开的项(单选模式为 string,多选模式为 string[]) */
23
+ value?: string | string[]
24
+ /** 是否允许多选 */
25
+ multiple?: boolean
26
+ /** 样式变体 */
27
+ variant?: 'default' | 'bordered' | 'shadow' | 'joined'
28
+ /** 图标样式 */
29
+ icon?: 'arrow' | 'plus' | 'none'
30
+ /** 是否有分隔线 */
31
+ divider?: boolean
32
+ /** 变化事件 */
33
+ onchange?: (value: string | string[]) => void
34
+ /** 自定义类名 */
35
+ class?: string
36
+ /** 自定义内容渲染 */
37
+ children?: Snippet<[AccordionItem]>
38
+ }
39
+
40
+ let {
41
+ items,
42
+ value = $bindable(undefined),
43
+ multiple = false,
44
+ variant = 'default',
45
+ icon = 'arrow',
46
+ divider = false,
47
+ onchange,
48
+ class: className = '',
49
+ children,
50
+ }: Props = $props()
51
+
52
+ const groupName = `accordion-${Math.random().toString(36).slice(2, 9)}`
53
+
54
+ function isExpanded(itemId: string): boolean {
55
+ if (value === undefined)
56
+ return false
57
+ if (multiple) {
58
+ return Array.isArray(value) && value.includes(itemId)
59
+ }
60
+ return value === itemId
61
+ }
62
+
63
+ function toggleItem(itemId: string) {
64
+ if (multiple) {
65
+ const current = Array.isArray(value) ? value : []
66
+ const newValue = current.includes(itemId)
67
+ ? current.filter(id => id !== itemId)
68
+ : [...current, itemId]
69
+ value = newValue
70
+ onchange?.(newValue)
71
+ }
72
+ else {
73
+ const newValue = value === itemId ? undefined : itemId
74
+ value = newValue as string
75
+ onchange?.(newValue as string)
76
+ }
77
+ }
78
+
79
+ const iconClass = $derived({
80
+ arrow: 'collapse-arrow',
81
+ plus: 'collapse-plus',
82
+ none: '',
83
+ }[icon] || 'collapse-arrow')
84
+
85
+ const containerClass = $derived(
86
+ cn(
87
+ variant === 'joined' && 'join join-vertical w-full',
88
+ className,
89
+ ),
90
+ )
91
+
92
+ function getItemClass(item: AccordionItem): string {
93
+ return cn(
94
+ 'collapse',
95
+ iconClass,
96
+ variant === 'bordered' && 'collapse-bordered border border-base-300',
97
+ variant === 'shadow' && 'shadow-md',
98
+ variant === 'joined' && 'join-item border border-base-300',
99
+ variant === 'default' && 'bg-base-100',
100
+ divider && variant !== 'joined' && 'border-b border-base-300',
101
+ item.disabled && 'opacity-50 pointer-events-none',
102
+ )
103
+ }
104
+ </script>
105
+
106
+ <div class={containerClass}>
107
+ {#each items as item (item.id)}
108
+ <div class={getItemClass(item)}>
109
+ {#if multiple}
110
+ <!-- 多选模式 - 使用 checkbox -->
111
+ <ToggleCheckbox
112
+ checked={isExpanded(item.id)}
113
+ disabled={item.disabled}
114
+ onchange={() => toggleItem(item.id)}
115
+ />
116
+ {:else}
117
+ <!-- 单选模式 - 使用 radio -->
118
+ <ToggleRadio
119
+ name={groupName}
120
+ checked={isExpanded(item.id)}
121
+ disabled={item.disabled}
122
+ onchange={() => toggleItem(item.id)}
123
+ />
124
+ {/if}
125
+
126
+ <div class='collapse-title font-semibold flex items-center gap-2'>
127
+ {#if item.icon}
128
+ <span class='text-lg'>{item.icon}</span>
129
+ {/if}
130
+ {item.title}
131
+ </div>
132
+
133
+ <div class='collapse-content text-sm'>
134
+ {#if children}
135
+ {@render children(item)}
136
+ {:else if item.content}
137
+ <p>{item.content}</p>
138
+ {/if}
139
+ </div>
140
+ </div>
141
+ {/each}
142
+ </div>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { AccordionItem } from './accordion-types.js';
3
+ interface Props {
4
+ /** 折叠项数据 */
5
+ items: AccordionItem[];
6
+ /** 当前展开的项(单选模式为 string,多选模式为 string[]) */
7
+ value?: string | string[];
8
+ /** 是否允许多选 */
9
+ multiple?: boolean;
10
+ /** 样式变体 */
11
+ variant?: 'default' | 'bordered' | 'shadow' | 'joined';
12
+ /** 图标样式 */
13
+ icon?: 'arrow' | 'plus' | 'none';
14
+ /** 是否有分隔线 */
15
+ divider?: boolean;
16
+ /** 变化事件 */
17
+ onchange?: (value: string | string[]) => void;
18
+ /** 自定义类名 */
19
+ class?: string;
20
+ /** 自定义内容渲染 */
21
+ children?: Snippet<[AccordionItem]>;
22
+ }
23
+ declare const Accordion: import("svelte").Component<Props, {}, "value">;
24
+ type Accordion = ReturnType<typeof Accordion>;
25
+ export default Accordion;
@@ -0,0 +1,116 @@
1
+ <!--
2
+ @h-ai/ui — ActionSheet(底部操作菜单)
3
+
4
+ 用法:
5
+ <ActionSheet
6
+ open={showActions}
7
+ items={[
8
+ { id: 'edit', label: '编辑' },
9
+ { id: 'delete', label: '删除', destructive: true },
10
+ ]}
11
+ onselect={(id) => handleAction(id)}
12
+ onclose={() => showActions = false}
13
+ />
14
+ -->
15
+ <script lang='ts'>
16
+ import type { ActionSheetItem } from './action-sheet-types.js'
17
+ import { cn } from '../../utils.js'
18
+
19
+ // eslint-disable-next-line no-import-assign -- type re-export
20
+ export type { ActionSheetItem }
21
+
22
+ interface Props {
23
+ /** 是否显示 */
24
+ open?: boolean
25
+ /** 操作列表 */
26
+ items: ActionSheetItem[]
27
+ /** 标题 */
28
+ title?: string
29
+ /** 取消按钮文字 */
30
+ cancelText?: string
31
+ /** 选择回调 */
32
+ onselect?: (id: string) => void
33
+ /** 关闭回调 */
34
+ onclose?: () => void
35
+ /** 额外 CSS 类 */
36
+ class?: string
37
+ }
38
+
39
+ const {
40
+ open = false,
41
+ items,
42
+ title,
43
+ cancelText = 'Cancel',
44
+ onselect,
45
+ onclose,
46
+ class: className,
47
+ }: Props = $props()
48
+
49
+ function handleSelect(id: string) {
50
+ onselect?.(id)
51
+ onclose?.()
52
+ }
53
+ </script>
54
+
55
+ {#if open}
56
+ <!-- 遮罩层 -->
57
+ <div
58
+ class='fixed inset-0 bg-black/50 z-50 transition-opacity'
59
+ role='button'
60
+ tabindex='-1'
61
+ onclick={onclose}
62
+ onkeydown={e => e.key === 'Escape' && onclose?.()}
63
+ ></div>
64
+
65
+ <!-- 操作面板 -->
66
+ <div
67
+ class={cn(
68
+ 'fixed bottom-0 left-0 right-0 z-50 bg-base-100 rounded-t-2xl hai-safe-bottom',
69
+ 'animate-[slideUp_0.25s_ease-out]',
70
+ className,
71
+ )}
72
+ >
73
+ {#if title}
74
+ <div class='text-center text-sm text-base-content/60 py-3 border-b border-base-200'>
75
+ {title}
76
+ </div>
77
+ {/if}
78
+
79
+ <div class='py-1'>
80
+ {#each items as item (item.id)}
81
+ <button
82
+ type='button'
83
+ class={cn(
84
+ 'w-full py-3.5 text-center text-base transition-colors',
85
+ 'active:bg-base-200',
86
+ item.destructive && 'text-error',
87
+ item.disabled && 'opacity-50 cursor-not-allowed',
88
+ !item.destructive && !item.disabled && 'text-base-content',
89
+ )}
90
+ disabled={item.disabled}
91
+ onclick={() => handleSelect(item.id)}
92
+ >
93
+ {item.label}
94
+ </button>
95
+ {/each}
96
+ </div>
97
+
98
+ <!-- 取消按钮 -->
99
+ <div class='border-t-4 border-base-200'>
100
+ <button
101
+ type='button'
102
+ class='w-full py-3.5 text-center text-base font-medium text-base-content active:bg-base-200'
103
+ onclick={onclose}
104
+ >
105
+ {cancelText}
106
+ </button>
107
+ </div>
108
+ </div>
109
+ {/if}
110
+
111
+ <style>
112
+ @keyframes slideUp {
113
+ from { transform: translateY(100%); }
114
+ to { transform: translateY(0); }
115
+ }
116
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { ActionSheetItem } from './action-sheet-types.js';
2
+ interface Props {
3
+ /** 是否显示 */
4
+ open?: boolean;
5
+ /** 操作列表 */
6
+ items: ActionSheetItem[];
7
+ /** 标题 */
8
+ title?: string;
9
+ /** 取消按钮文字 */
10
+ cancelText?: string;
11
+ /** 选择回调 */
12
+ onselect?: (id: string) => void;
13
+ /** 关闭回调 */
14
+ onclose?: () => void;
15
+ /** 额外 CSS 类 */
16
+ class?: string;
17
+ }
18
+ declare const ActionSheet: import("svelte").Component<Props, {
19
+ ActionSheetItem: typeof ActionSheetItem;
20
+ }, "">;
21
+ type ActionSheet = ReturnType<typeof ActionSheet>;
22
+ export default ActionSheet;
@@ -0,0 +1,67 @@
1
+ <!--
2
+ @component Alert
3
+ 警告框组件,使用 tabler icon 替代 emoji,更精致。
4
+ -->
5
+ <script lang='ts'>
6
+ import type { AlertProps } from '../../types.js'
7
+ import { uiM } from '../../messages.js'
8
+ import { cn, getAlertVariantClass } from '../../utils.js'
9
+ import IconButton from '../primitives/IconButton.svelte'
10
+
11
+ const {
12
+ variant = 'info',
13
+ title = '',
14
+ dismissible = false,
15
+ class: className = '',
16
+ onclose,
17
+ children,
18
+ }: AlertProps = $props()
19
+
20
+ let visible = $state(true)
21
+
22
+ const alertClass = $derived(
23
+ cn(
24
+ 'alert',
25
+ getAlertVariantClass(variant),
26
+ className,
27
+ ),
28
+ )
29
+
30
+ // 图标映射:使用 tabler icon 类
31
+ const iconMap: Record<string, string> = {
32
+ info: 'icon-[tabler--info-circle]',
33
+ success: 'icon-[tabler--circle-check]',
34
+ warning: 'icon-[tabler--alert-triangle]',
35
+ error: 'icon-[tabler--circle-x]',
36
+ }
37
+
38
+ function handleClose() {
39
+ visible = false
40
+ onclose?.()
41
+ }
42
+ </script>
43
+
44
+ {#if visible}
45
+ <div class={alertClass} role='alert'>
46
+ <span class='{iconMap[variant] ?? iconMap.info} size-5 shrink-0'></span>
47
+
48
+ <div>
49
+ {#if title}
50
+ <h3 class='font-semibold text-sm'>{title}</h3>
51
+ {/if}
52
+ {#if children}
53
+ <div class='text-sm'>
54
+ {@render children()}
55
+ </div>
56
+ {/if}
57
+ </div>
58
+
59
+ {#if dismissible}
60
+ <IconButton size='sm' variant='ghost' label={uiM('common_close')} onclick={handleClose}>
61
+ {#snippet children()}
62
+ <span class='icon-[tabler--x] size-4'></span>
63
+ {/snippet}
64
+ </IconButton>
65
+ {/if}
66
+ </div>
67
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { AlertProps } from '../../types.js';
2
+ /**
3
+ * Alert
4
+ * 警告框组件,使用 tabler icon 替代 emoji,更精致。
5
+ */
6
+ declare const Alert: import("svelte").Component<AlertProps, {}, "">;
7
+ type Alert = ReturnType<typeof Alert>;
8
+ export default Alert;