@h-ai/ui 0.1.0-alpha.30 → 0.1.0-alpha.32

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 (36) hide show
  1. package/README.md +38 -3
  2. package/dist/components/compounds/Combobox.svelte +59 -20
  3. package/dist/components/compounds/MessageContainer.svelte +37 -64
  4. package/dist/components/compounds/Modal.svelte +24 -40
  5. package/dist/components/compounds/Pagination.svelte +3 -5
  6. package/dist/components/primitives/Select.svelte +293 -46
  7. package/dist/components/primitives/Textarea.svelte +28 -15
  8. package/dist/components/scenes/ai/AiDocumentEditor.svelte +34 -7
  9. package/dist/components/scenes/ai/MarkdownRenderer.svelte +46 -5
  10. package/dist/components/scenes/ai/document-parse.d.ts +2 -0
  11. package/dist/components/scenes/ai/document-parse.js +16 -17
  12. package/dist/components/scenes/ai/document-types.d.ts +4 -0
  13. package/dist/components/scenes/ai/markdown-parse.d.ts +2 -0
  14. package/dist/components/scenes/ai/markdown-parse.js +17 -20
  15. package/dist/components/scenes/ai/safe-html.d.ts +16 -0
  16. package/dist/components/scenes/ai/safe-html.js +284 -0
  17. package/dist/components/scenes/app/FeedbackModal.svelte +3 -2
  18. package/dist/components/scenes/app/FeedbackModal.svelte.d.ts +1 -0
  19. package/dist/components/scenes/app/SettingsModal.svelte +4 -2
  20. package/dist/components/scenes/app/SettingsModal.svelte.d.ts +1 -0
  21. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte +3 -0
  22. package/dist/components/scenes/crud/CrudDeleteConfirm.svelte.d.ts +1 -0
  23. package/dist/components/scenes/crud/CrudDetailDrawer.svelte +4 -1
  24. package/dist/components/scenes/crud/CrudDetailDrawer.svelte.d.ts +1 -0
  25. package/dist/components/scenes/crud/CrudDetailPanel.svelte +4 -1
  26. package/dist/components/scenes/crud/CrudDetailPanel.svelte.d.ts +1 -0
  27. package/dist/components/scenes/crud/CrudEditPanel.svelte +9 -7
  28. package/dist/components/scenes/crud/CrudEditPanel.svelte.d.ts +1 -0
  29. package/dist/components/scenes/crud/CrudFilterBar.svelte +15 -13
  30. package/dist/components/scenes/crud/CrudFilterBar.svelte.d.ts +1 -0
  31. package/dist/components/scenes/types.d.ts +4 -0
  32. package/dist/styles/global.css +5 -0
  33. package/dist/types.d.ts +5 -5
  34. package/dist/utils.d.ts +13 -0
  35. package/dist/utils.js +25 -1
  36. package/package.json +2 -2
@@ -50,6 +50,7 @@
50
50
  onclose,
51
51
  editFormExtra,
52
52
  editingItem = null,
53
+ class: className = '',
53
54
  ...restProps
54
55
  }: {
55
56
  open?: boolean
@@ -70,6 +71,7 @@
70
71
  onclose?: () => void
71
72
  editFormExtra?: Snippet<[Record<string, unknown> | null, 'create' | 'edit']>
72
73
  editingItem?: Record<string, unknown> | null
74
+ class?: string
73
75
  } & DataAttributes = $props()
74
76
 
75
77
  const dataAttributes = $derived(getDataAttributes(restProps))
@@ -171,13 +173,12 @@
171
173
  size={controlSize}
172
174
  value={String(fieldValue ?? '')}
173
175
  disabled={submitting || isReadonly}
176
+ options={[
177
+ { value: '', label: placeholder || uiM('crud_filter_all') },
178
+ ...opts.map(opt => ({ value: String(opt.value), label: opt.label })),
179
+ ]}
174
180
  onchange={value => updateField(field.id, value)}
175
- >
176
- <option value="">{placeholder || uiM('crud_filter_all')}</option>
177
- {#each opts as opt (String(opt.value))}
178
- <option value={String(opt.value)}>{opt.label}</option>
179
- {/each}
180
- </Select>
181
+ />
181
182
  </FormField>
182
183
 
183
184
  {:else if field.type === 'multi-select'}
@@ -255,6 +256,7 @@
255
256
  {#if variant === 'modal'}
256
257
  <Modal
257
258
  bind:open
259
+ class={className}
258
260
  {title}
259
261
  size={modalSize}
260
262
  width={modalWidth}
@@ -271,7 +273,7 @@
271
273
  {/snippet}
272
274
  </Modal>
273
275
  {:else}
274
- <Drawer bind:open {title} position='right' {size} width={drawerWidth} onclose={handleClose} closeOnBackdrop={false}>
276
+ <Drawer bind:open {title} class={className} position='right' {size} width={drawerWidth} onclose={handleClose} closeOnBackdrop={false}>
275
277
  <form onsubmit={handleSubmit} class={drawerFormClass}>
276
278
  {@render formFields()}
277
279
  </form>
@@ -42,6 +42,7 @@ type $$ComponentProps = {
42
42
  onclose?: () => void;
43
43
  editFormExtra?: Snippet<[Record<string, unknown> | null, 'create' | 'edit']>;
44
44
  editingItem?: Record<string, unknown> | null;
45
+ class?: string;
45
46
  } & DataAttributes;
46
47
  /**
47
48
  * CrudEditPanel
@@ -7,7 +7,7 @@
7
7
  <script lang='ts'>
8
8
  import type { DataAttributes } from '../../../types.js'
9
9
  import { uiM } from '../../../messages.js'
10
- import { getDataAttributes } from '../../../utils.js'
10
+ import { cn, getDataAttributes } from '../../../utils.js'
11
11
  import BareButton from '../../primitives/BareButton.svelte'
12
12
  import Input from '../../primitives/Input.svelte'
13
13
  import Select from '../../primitives/Select.svelte'
@@ -34,6 +34,7 @@
34
34
  onsearch,
35
35
  onfilterchange,
36
36
  onreset,
37
+ class: className = '',
37
38
  ...restProps
38
39
  }: {
39
40
  searchable?: boolean
@@ -44,6 +45,7 @@
44
45
  onsearch?: (search: string) => void
45
46
  onfilterchange?: (filters: Record<string, unknown>) => void
46
47
  onreset?: () => void
48
+ class?: string
47
49
  } & DataAttributes = $props()
48
50
 
49
51
  const dataAttributes = $derived(getDataAttributes(restProps))
@@ -120,7 +122,7 @@
120
122
  }
121
123
  </script>
122
124
 
123
- <div {...dataAttributes} class='flex flex-wrap items-center gap-2 [&_.fieldset]:m-0 [&_.fieldset]:min-w-0'>
125
+ <div {...dataAttributes} class={cn('flex flex-wrap items-center gap-2 [&_.fieldset]:m-0 [&_.fieldset]:min-w-0', className)}>
124
126
  {#if searchable}
125
127
  <div class='relative w-full sm:w-64 md:w-72'>
126
128
  <span class='icon-[tabler--search] pointer-events-none absolute left-3 top-1/2 z-10 size-4 -translate-y-1/2 text-base-content/35'></span>
@@ -170,12 +172,13 @@
170
172
  size='sm'
171
173
  class='h-8 border-base-content/20 bg-base-100 shadow-none'
172
174
  value={String(filterValues[field.id] ?? '')}
175
+ options={[
176
+ { value: '', label: uiM('crud_filter_all') },
177
+ { value: 'true', label: uiM('crud_filter_yes') },
178
+ { value: 'false', label: uiM('crud_filter_no') },
179
+ ]}
173
180
  onchange={(value: string) => handleFilterChange(field.id, value)}
174
- >
175
- <option value="">{uiM('crud_filter_all')}</option>
176
- <option value='true'>{uiM('crud_filter_yes')}</option>
177
- <option value='false'>{uiM('crud_filter_no')}</option>
178
- </Select>
181
+ />
179
182
  </div>
180
183
  {:else if isDateField(field)}
181
184
  <div class='w-36 shrink-0'>
@@ -207,13 +210,12 @@
207
210
  size='sm'
208
211
  class='h-8 border-base-content/20 bg-base-100 shadow-none'
209
212
  value={String(filterValues[field.id] ?? '')}
213
+ options={[
214
+ { value: '', label: uiM('crud_filter_all') },
215
+ ...opts.map(opt => ({ value: String(opt.value), label: opt.label })),
216
+ ]}
210
217
  onchange={(value: string) => handleFilterChange(field.id, value)}
211
- >
212
- <option value="">{uiM('crud_filter_all')}</option>
213
- {#each opts as opt (String(opt.value))}
214
- <option value={String(opt.value)}>{opt.label}</option>
215
- {/each}
216
- </Select>
218
+ />
217
219
  </div>
218
220
  {:else if isTextField(field)}
219
221
  <div class='w-44 shrink-0'>
@@ -26,6 +26,7 @@ type $$ComponentProps = {
26
26
  onsearch?: (search: string) => void;
27
27
  onfilterchange?: (filters: Record<string, unknown>) => void;
28
28
  onreset?: () => void;
29
+ class?: string;
29
30
  } & DataAttributes;
30
31
  /**
31
32
  * CrudFilterBar
@@ -544,6 +544,8 @@ export interface HashDisplayProps extends DataAttributes {
544
544
  export interface MarkdownRendererProps extends DataAttributes {
545
545
  /** Markdown 源文本 */
546
546
  content?: string;
547
+ /** 文本字号,支持 number(按 px)或任意 CSS 长度字符串 */
548
+ fontSize?: string | number;
547
549
  /** 自定义类名 */
548
550
  class?: string;
549
551
  /** 是否显示代码块复制按钮(默认 true) */
@@ -552,6 +554,8 @@ export interface MarkdownRendererProps extends DataAttributes {
552
554
  enableHighlight?: boolean;
553
555
  /** 是否将换行符转换为 <br>(默认 true,适合 AI 输出) */
554
556
  breaks?: boolean;
557
+ /** 是否按安全白名单解析原始 HTML 标签(默认 false) */
558
+ allowHtmlTags?: boolean;
555
559
  }
556
560
  /**
557
561
  * 签名展示属性
@@ -89,6 +89,11 @@ input::-webkit-credentials-auto-fill-button {
89
89
  color: oklch(0.55 0 0);
90
90
  }
91
91
 
92
+ /* ─── DaisyUI 组件微调:fieldset-legend 间距修正 ─── */
93
+ .fieldset-legend {
94
+ justify-content: flex-start !important;
95
+ }
96
+
92
97
  .modal-box {
93
98
  border-radius: 0.75rem;
94
99
  }
package/dist/types.d.ts CHANGED
@@ -286,7 +286,7 @@ export interface SelectOption<T = string> {
286
286
  export interface SelectProps<T = string> extends DataAttributes {
287
287
  /** 值 */
288
288
  value?: T;
289
- /** 选项(使用 options 或 children 二选一) */
289
+ /** 选项 */
290
290
  options?: SelectOption<T>[];
291
291
  /** 占位符 */
292
292
  placeholder?: string;
@@ -296,18 +296,18 @@ export interface SelectProps<T = string> extends DataAttributes {
296
296
  disabled?: boolean;
297
297
  /** 是否必填 */
298
298
  required?: boolean;
299
+ /** 是否可清空 */
300
+ clearable?: boolean;
301
+ /** 是否可筛选(启用后可在输入框内输入过滤选项) */
302
+ filterable?: boolean;
299
303
  /** 错误消息 */
300
304
  error?: string;
301
- /** 自定义验证消息(用于覆盖浏览器原生验证提示) */
302
- validationMessage?: string;
303
305
  /** 自定义类名 */
304
306
  class?: string;
305
307
  /** 元素 ID */
306
308
  id?: string;
307
309
  /** 变化事件 */
308
310
  onchange?: (value: T) => void;
309
- /** 子元素(原生 option 元素) */
310
- children?: Snippet;
311
311
  }
312
312
  /**
313
313
  * 复选框属性
package/dist/utils.d.ts CHANGED
@@ -49,3 +49,16 @@ export declare function getProgressVariantClass(variant: Variant): string;
49
49
  * 生成唯一 ID
50
50
  */
51
51
  export declare function generateId(prefix?: string): string;
52
+ /**
53
+ * Portal action:将节点移动到目标容器(默认 document.body)下渲染。
54
+ *
55
+ * 用于弹出层(下拉、气泡等)逃逸祖先的 `overflow: hidden` 裁剪与
56
+ * 堆叠上下文(stacking context)限制,避免被相邻控件遮挡。
57
+ *
58
+ * @param node - 要移动的节点
59
+ * @param target - 目标容器或选择器;默认 body
60
+ */
61
+ export declare function portal(node: HTMLElement, target?: HTMLElement | string): {
62
+ update(next: HTMLElement | string): void;
63
+ destroy(): void;
64
+ };
package/dist/utils.js CHANGED
@@ -36,7 +36,7 @@ export function getDataAttributes(props) {
36
36
  */
37
37
  const VARIANT_MAPS = {
38
38
  btn: {
39
- default: 'btn-neutral',
39
+ default: '',
40
40
  primary: 'btn-primary',
41
41
  secondary: 'btn-secondary',
42
42
  success: 'btn-success',
@@ -176,3 +176,27 @@ export function getProgressVariantClass(variant) {
176
176
  export function generateId(prefix = 'hai') {
177
177
  return `${prefix}-${Math.random().toString(36).slice(2, 9)}`;
178
178
  }
179
+ /**
180
+ * Portal action:将节点移动到目标容器(默认 document.body)下渲染。
181
+ *
182
+ * 用于弹出层(下拉、气泡等)逃逸祖先的 `overflow: hidden` 裁剪与
183
+ * 堆叠上下文(stacking context)限制,避免被相邻控件遮挡。
184
+ *
185
+ * @param node - 要移动的节点
186
+ * @param target - 目标容器或选择器;默认 body
187
+ */
188
+ export function portal(node, target = 'body') {
189
+ function mount(to) {
190
+ const targetEl = typeof to === 'string' ? document.querySelector(to) : to;
191
+ targetEl?.appendChild(node);
192
+ }
193
+ mount(target);
194
+ return {
195
+ update(next) {
196
+ mount(next);
197
+ },
198
+ destroy() {
199
+ node.parentNode?.removeChild(node);
200
+ },
201
+ };
202
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/ui",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.30",
4
+ "version": "0.1.0-alpha.32",
5
5
  "description": "Hai Framework UI component library for Svelte 5 Runes.",
6
6
  "license": "Apache-2.0",
7
7
  "svelte": "./dist/index.js",
@@ -51,7 +51,7 @@
51
51
  "mermaid": "^11.12.0",
52
52
  "shiki": "^4.0.2",
53
53
  "tailwind-merge": "^3.5.0",
54
- "@h-ai/core": "0.1.0-alpha.30"
54
+ "@h-ai/core": "0.1.0-alpha.32"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@sveltejs/package": "^2.5.7",