@h-ai/ui 0.1.0-alpha.33 → 0.1.0-alpha.35

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 (45) hide show
  1. package/README.md +24 -5
  2. package/auto-import.js +2 -2
  3. package/dist/components/compounds/Combobox.svelte +12 -4
  4. package/dist/components/compounds/Combobox.svelte.d.ts +4 -1
  5. package/dist/components/compounds/DatePicker.svelte +19 -4
  6. package/dist/components/compounds/DatePicker.svelte.d.ts +4 -1
  7. package/dist/components/compounds/TagInput.svelte +36 -31
  8. package/dist/components/control-size.d.ts +18 -0
  9. package/dist/components/control-size.js +18 -0
  10. package/dist/components/primitives/Input.svelte +4 -25
  11. package/dist/components/primitives/Select.svelte +4 -10
  12. package/dist/components/scenes/ai/AiDocumentEditor.svelte +203 -22
  13. package/dist/components/scenes/ai/document-download.js +19 -2
  14. package/dist/components/scenes/ai/document-parse.d.ts +25 -2
  15. package/dist/components/scenes/ai/document-parse.js +137 -11
  16. package/dist/components/scenes/ai/index.d.ts +1 -1
  17. package/dist/components/scenes/ai/mermaid-host-sync.d.ts +34 -0
  18. package/dist/components/scenes/ai/mermaid-host-sync.js +35 -0
  19. package/dist/components/scenes/ai/mermaid-render.d.ts +5 -0
  20. package/dist/components/scenes/ai/mermaid-render.js +7 -0
  21. package/dist/components/scenes/charts/Chart.svelte +152 -0
  22. package/dist/components/scenes/charts/Chart.svelte.d.ts +5 -0
  23. package/dist/components/scenes/charts/chart-theme.d.ts +23 -0
  24. package/dist/components/scenes/charts/chart-theme.js +44 -0
  25. package/dist/components/scenes/charts/chart-types.d.ts +77 -0
  26. package/dist/components/scenes/charts/chart-types.js +7 -0
  27. package/dist/components/scenes/charts/index.d.ts +8 -0
  28. package/dist/components/scenes/charts/index.js +7 -0
  29. package/dist/components/scenes/charts/renderers/AreaChart.svelte +18 -0
  30. package/dist/components/scenes/charts/renderers/AreaChart.svelte.d.ts +5 -0
  31. package/dist/components/scenes/charts/renderers/BarChart.svelte +18 -0
  32. package/dist/components/scenes/charts/renderers/BarChart.svelte.d.ts +5 -0
  33. package/dist/components/scenes/charts/renderers/LineChart.svelte +571 -0
  34. package/dist/components/scenes/charts/renderers/LineChart.svelte.d.ts +19 -0
  35. package/dist/components/scenes/charts/renderers/PieChart.svelte +18 -0
  36. package/dist/components/scenes/charts/renderers/PieChart.svelte.d.ts +5 -0
  37. package/dist/components/scenes/charts/renderers/ScatterChart.svelte +18 -0
  38. package/dist/components/scenes/charts/renderers/ScatterChart.svelte.d.ts +5 -0
  39. package/dist/components/scenes/iam/PasswordInput.svelte +4 -15
  40. package/dist/components/scenes/index.d.ts +1 -0
  41. package/dist/components/scenes/index.js +2 -0
  42. package/dist/messages/en-US.json +2 -0
  43. package/dist/messages/zh-CN.json +2 -0
  44. package/dist/types.d.ts +1 -0
  45. package/package.json +3 -2
package/README.md CHANGED
@@ -187,11 +187,11 @@ components/
187
187
 
188
188
  #### Bits UI headless 交互
189
189
 
190
- | 组件 | 描述 | 主要属性 |
191
- | ------------ | --------------------------- | --------------------------------------------------- |
192
- | `Combobox` | 可搜索下拉选择(单选/多选) | `options`, `value`, `multiple`, `placeholder` |
193
- | `Calendar` | 独立日历 | `value: DateValue`, `minValue`, `maxValue` |
194
- | `DatePicker` | 日期输入+弹出 | `value: DateValue`, `minValue`, `maxValue`, `error` |
190
+ | 组件 | 描述 | 主要属性 |
191
+ | ------------ | --------------------------- | ----------------------------------------------------------- |
192
+ | `Combobox` | 可搜索下拉选择(单选/多选) | `options`, `value`, `multiple`, `placeholder`, `size` |
193
+ | `Calendar` | 独立日历 | `value: DateValue`, `minValue`, `maxValue` |
194
+ | `DatePicker` | 日期输入+弹出 | `value: DateValue`, `minValue`, `maxValue`, `error`, `size` |
195
195
 
196
196
  > 日期值使用 `@internationalized/date` 的 `DateValue` / `CalendarDate` 类型。
197
197
 
@@ -309,6 +309,25 @@ components/
309
309
  />
310
310
  ```
311
311
 
312
+ #### Charts 图表
313
+
314
+ `Chart type='line'` 默认透传 LayerChart 原生折线图;需要监控看板常见的“分段线 + 圆点 + 最近点 hover + 竖向参考线”时,使用 `lineVariant='segmented-point'`:
315
+
316
+ ```svelte
317
+ <Chart
318
+ type='line'
319
+ data={trendData}
320
+ x='label'
321
+ y={['rateLimit', 'circuitBreak']}
322
+ series={trendSeries}
323
+ lineVariant='segmented-point'
324
+ tooltipMode='nearest'
325
+ showCrosshair
326
+ legend
327
+ grid
328
+ />
329
+ ```
330
+
312
331
  #### CRUD 场景(5 个)
313
332
 
314
333
  | 组件 | 描述 | 主要属性 / 能力 |
package/auto-import.js CHANGED
@@ -232,9 +232,9 @@ function autoImportHaiUi() {
232
232
  return { code: content }
233
233
  }
234
234
 
235
- // 跳过 @h-ai/ui 包自身的文件,避免重复导入
235
+ // 自动导入只服务应用源码;第三方依赖和 @h-ai/ui 自身必须保持原样,避免改写依赖内部的同名组件。
236
236
  const normalizedPath = filename.replace(WINDOWS_PATH_SEPARATOR_REGEX, '/')
237
- if (normalizedPath.includes('/packages/ui/') || normalizedPath.includes('/@h-ai/ui/')) {
237
+ if (normalizedPath.includes('/node_modules/') || normalizedPath.includes('/packages/ui/') || normalizedPath.includes('/@h-ai/ui/')) {
238
238
  return { code: content }
239
239
  }
240
240
 
@@ -8,6 +8,7 @@
8
8
  @prop {string | string[]} value - 选中值(双向绑定,单选为 string,多选为 string[])
9
9
  @prop {boolean} multiple - 是否多选模式
10
10
  @prop {string} placeholder - 输入框占位符
11
+ @prop {Size} size - 输入框尺寸
11
12
  @prop {boolean} disabled - 是否禁用
12
13
  @prop {string} error - 错误消息
13
14
  @prop {string} label - 表单标签
@@ -33,10 +34,11 @@
33
34
  />
34
35
  -->
35
36
  <script lang='ts'>
36
- import type { DataAttributes } from '../../types.js'
37
+ import type { DataAttributes, Size } from '../../types.js'
37
38
  import { Combobox } from 'bits-ui'
38
39
  import { uiM } from '../../messages.js'
39
40
  import { cn, getDataAttributes } from '../../utils.js'
41
+ import { getFormControlSizeClasses } from '../control-size.js'
40
42
  import BareButton from '../primitives/BareButton.svelte'
41
43
 
42
44
  /** 选项定义 */
@@ -60,6 +62,8 @@
60
62
  multiple?: boolean
61
63
  /** 输入框占位符 */
62
64
  placeholder?: string
65
+ /** 尺寸 */
66
+ size?: Size
63
67
  /** 是否禁用 */
64
68
  disabled?: boolean
65
69
  /** 错误消息 */
@@ -77,6 +81,7 @@
77
81
  value = $bindable(),
78
82
  multiple = false,
79
83
  placeholder = '',
84
+ size = 'md',
80
85
  disabled = false,
81
86
  error,
82
87
  label: fieldLabel,
@@ -86,6 +91,7 @@
86
91
  }: Props & DataAttributes = $props()
87
92
 
88
93
  const dataAttributes = $derived(getDataAttributes(restProps))
94
+ const sizeClasses = $derived(getFormControlSizeClasses(size))
89
95
  // 为未提供 value 时设置初始默认值(仅在初始化时执行一次)
90
96
  // 统一以空字符串初始化,避免在初始化阶段捕获 multiple 的初始值。
91
97
  // 多选模式会通过 multiVal 派生为 [] 传给 Combobox.Root。
@@ -214,7 +220,8 @@
214
220
  <div class='relative'>
215
221
  <div
216
222
  class={cn(
217
- 'min-h-10 rounded-lg border bg-base-100 flex flex-wrap gap-1.5 items-center py-1.5 pl-2.5 pr-9 transition-[border-color,box-shadow] duration-150',
223
+ 'rounded-lg border bg-base-100 flex flex-wrap gap-1.5 items-center py-1 pl-2.5 pr-9 transition-[border-color,box-shadow] duration-150',
224
+ sizeClasses.minHeight,
218
225
  disabled ? 'opacity-50 cursor-not-allowed bg-base-200' : 'cursor-text',
219
226
  controlStateClass,
220
227
  )}
@@ -237,7 +244,7 @@
237
244
 
238
245
  <Combobox.Input
239
246
  bind:ref={inputRef}
240
- class='flex-1 min-w-20 bg-transparent py-0.5 text-sm outline-none placeholder:text-base-content/40'
247
+ class={cn('flex-1 min-w-20 bg-transparent py-0.5 outline-none placeholder:text-base-content/40', sizeClasses.spacing)}
241
248
  placeholder={selectedOptions.length === 0 ? placeholder : ''}
242
249
  {disabled}
243
250
  oninput={handleInput}
@@ -307,7 +314,8 @@
307
314
  <Combobox.Input
308
315
  bind:ref={inputRef}
309
316
  class={cn(
310
- 'h-10 w-full rounded-lg border bg-base-100 pl-3 pr-9 text-sm outline-none transition-[border-color,box-shadow] duration-150 placeholder:text-base-content/40',
317
+ 'w-full rounded-lg border bg-base-100 pr-9 outline-none transition-[border-color,box-shadow] duration-150 placeholder:text-base-content/40',
318
+ sizeClasses.control,
311
319
  controlStateClass,
312
320
  disabled && 'opacity-50 cursor-not-allowed',
313
321
  )}
@@ -1,4 +1,4 @@
1
- import type { DataAttributes } from '../../types.js';
1
+ import type { DataAttributes, Size } from '../../types.js';
2
2
  import { Combobox } from 'bits-ui';
3
3
  /** 选项定义 */
4
4
  interface Option {
@@ -20,6 +20,8 @@ interface Props {
20
20
  multiple?: boolean;
21
21
  /** 输入框占位符 */
22
22
  placeholder?: string;
23
+ /** 尺寸 */
24
+ size?: Size;
23
25
  /** 是否禁用 */
24
26
  disabled?: boolean;
25
27
  /** 错误消息 */
@@ -42,6 +44,7 @@ type $$ComponentProps = Props & DataAttributes;
42
44
  * @prop {string | string[]} value - 选中值(双向绑定,单选为 string,多选为 string[])
43
45
  * @prop {boolean} multiple - 是否多选模式
44
46
  * @prop {string} placeholder - 输入框占位符
47
+ * @prop {Size} size - 输入框尺寸
45
48
  * @prop {boolean} disabled - 是否禁用
46
49
  * @prop {string} error - 错误消息
47
50
  * @prop {string} label - 表单标签
@@ -7,6 +7,7 @@
7
7
  @prop {DateValue} minValue - 最小可选日期
8
8
  @prop {DateValue} maxValue - 最大可选日期
9
9
  @prop {string} placeholder - 输入框占位文本
10
+ @prop {Size} size - 输入框尺寸
10
11
  @prop {boolean} disabled - 是否禁用
11
12
  @prop {string} error - 错误消息
12
13
  @prop {function} onchange - 日期变更回调
@@ -22,9 +23,10 @@
22
23
  -->
23
24
  <script lang='ts'>
24
25
  import type { DateValue } from '@internationalized/date'
25
- import type { DataAttributes } from '../../types.js'
26
+ import type { DataAttributes, Size } from '../../types.js'
26
27
  import { DatePicker as BitsDatePicker } from 'bits-ui'
27
- import { getDataAttributes } from '../../utils.js'
28
+ import { cn, getDataAttributes } from '../../utils.js'
29
+ import { getFormControlSizeClasses } from '../control-size.js'
28
30
 
29
31
  interface Props {
30
32
  /** 选中日期(双向绑定) */
@@ -39,6 +41,8 @@
39
41
  isDateUnavailable?: (date: DateValue) => boolean
40
42
  /** 是否禁用 */
41
43
  disabled?: boolean
44
+ /** 尺寸 */
45
+ size?: Size
42
46
  /** 错误消息 */
43
47
  error?: string
44
48
  /** 自定义类名 */
@@ -54,6 +58,7 @@
54
58
  weekStartsOn = 1,
55
59
  isDateUnavailable,
56
60
  disabled = false,
61
+ size = 'md',
57
62
  error,
58
63
  class: className = '',
59
64
  onchange,
@@ -61,6 +66,7 @@
61
66
  }: Props & DataAttributes = $props()
62
67
 
63
68
  const dataAttributes = $derived(getDataAttributes(restProps))
69
+ const sizeClasses = $derived(getFormControlSizeClasses(size))
64
70
  </script>
65
71
 
66
72
  <div {...dataAttributes} class='fieldset w-full {className}'>
@@ -73,12 +79,21 @@
73
79
  {disabled}
74
80
  onValueChange={v => onchange?.(v)}
75
81
  >
76
- <BitsDatePicker.Input class="input flex items-center gap-0.5 pr-2 {error ? 'input-error' : ''}">
82
+ <BitsDatePicker.Input
83
+ class={cn(
84
+ 'flex w-full items-center gap-0.5 rounded-lg border bg-base-100 pr-2 transition-[border-color,box-shadow] duration-150',
85
+ sizeClasses.control,
86
+ error
87
+ ? 'border-error/60 focus-within:ring-2 focus-within:ring-error/15'
88
+ : 'border-base-content/15 hover:border-base-content/25 focus-within:border-primary/50 focus-within:ring-2 focus-within:ring-primary/10',
89
+ disabled && 'cursor-not-allowed opacity-50',
90
+ )}
91
+ >
77
92
  {#snippet children({ segments })}
78
93
  {#each segments as { part, value: segValue }, index (`${part}-${index}`)}
79
94
  <BitsDatePicker.Segment
80
95
  {part}
81
- class='rounded px-0.5 py-0.5 text-sm tabular-nums focus:bg-primary focus:text-primary-content focus:outline-none data-[type=literal]:px-0 data-[type=literal]:text-base-content/50'
96
+ class='rounded px-0.5 py-0.5 tabular-nums focus:bg-primary focus:text-primary-content focus:outline-none data-[type=literal]:px-0 data-[type=literal]:text-base-content/50'
82
97
  >
83
98
  {segValue}
84
99
  </BitsDatePicker.Segment>
@@ -1,5 +1,5 @@
1
1
  import type { DateValue } from '@internationalized/date';
2
- import type { DataAttributes } from '../../types.js';
2
+ import type { DataAttributes, Size } from '../../types.js';
3
3
  interface Props {
4
4
  /** 选中日期(双向绑定) */
5
5
  value?: DateValue;
@@ -13,6 +13,8 @@ interface Props {
13
13
  isDateUnavailable?: (date: DateValue) => boolean;
14
14
  /** 是否禁用 */
15
15
  disabled?: boolean;
16
+ /** 尺寸 */
17
+ size?: Size;
16
18
  /** 错误消息 */
17
19
  error?: string;
18
20
  /** 自定义类名 */
@@ -30,6 +32,7 @@ type $$ComponentProps = Props & DataAttributes;
30
32
  * @prop {DateValue} minValue - 最小可选日期
31
33
  * @prop {DateValue} maxValue - 最大可选日期
32
34
  * @prop {string} placeholder - 输入框占位文本
35
+ * @prop {Size} size - 输入框尺寸
33
36
  * @prop {boolean} disabled - 是否禁用
34
37
  * @prop {string} error - 错误消息
35
38
  * @prop {function} onchange - 日期变更回调
@@ -10,7 +10,8 @@
10
10
  <script lang='ts'>
11
11
  import type { DataAttributes, TagInputProps } from '../../types.js'
12
12
  import { uiM } from '../../messages.js'
13
- import { cn, getDataAttributes, getInputSizeClass } from '../../utils.js'
13
+ import { cn, getDataAttributes } from '../../utils.js'
14
+ import { getFormControlSizeClasses } from '../control-size.js'
14
15
  import BareInput from '../primitives/BareInput.svelte'
15
16
  import Tag from '../primitives/Tag.svelte'
16
17
 
@@ -27,6 +28,7 @@
27
28
  }: TagInputProps & DataAttributes = $props()
28
29
 
29
30
  const dataAttributes = $derived(getDataAttributes(restProps))
31
+ const sizeClasses = $derived(getFormControlSizeClasses(size))
30
32
  let inputValue = $state('')
31
33
  let inputElement = $state<HTMLInputElement | undefined>(undefined)
32
34
 
@@ -34,9 +36,10 @@
34
36
 
35
37
  const containerClass = $derived(
36
38
  cn(
37
- 'input flex flex-wrap items-center gap-1 min-h-[2.5rem] h-auto py-1',
38
- getInputSizeClass(size),
39
- disabled && 'input-disabled',
39
+ 'flex h-auto w-full flex-wrap items-center gap-1 rounded-lg border border-base-content/15 bg-base-100 py-1 transition-[border-color,box-shadow] duration-150 focus-within:border-primary/50 focus-within:ring-2 focus-within:ring-primary/10',
40
+ sizeClasses.minHeight,
41
+ sizeClasses.spacing,
42
+ disabled && 'cursor-not-allowed opacity-50',
40
43
  className,
41
44
  ),
42
45
  )
@@ -79,32 +82,34 @@
79
82
  }
80
83
  </script>
81
84
 
82
- <div {...dataAttributes}
83
- class={containerClass}
84
- onclick={() => inputElement?.focus()}
85
- onkeydown={e => e.key === 'Enter' && inputElement?.focus()}
86
- role='textbox'
87
- tabindex='-1'
88
- >
89
- {#each tags as tag, index (index)}
90
- <Tag
91
- text={tag}
92
- size='sm'
93
- closable={!disabled}
94
- onclose={() => removeTag(index)}
95
- />
96
- {/each}
85
+ <div {...dataAttributes} class='fieldset w-full'>
86
+ <div
87
+ class={containerClass}
88
+ onclick={() => inputElement?.focus()}
89
+ onkeydown={e => e.key === 'Enter' && inputElement?.focus()}
90
+ role='textbox'
91
+ tabindex='-1'
92
+ >
93
+ {#each tags as tag, index (index)}
94
+ <Tag
95
+ text={tag}
96
+ size='sm'
97
+ closable={!disabled}
98
+ onclose={() => removeTag(index)}
99
+ />
100
+ {/each}
97
101
 
98
- {#if canAddMore && !disabled}
99
- <BareInput
100
- type='text'
101
- class='flex-1 min-w-[100px] bg-transparent border-none outline-none text-sm'
102
- bind:value={inputValue}
103
- bind:inputRef={inputElement}
104
- placeholder={displayPlaceholder}
105
- {disabled}
106
- onkeydown={handleKeydown}
107
- onblur={handleBlur}
108
- />
109
- {/if}
102
+ {#if canAddMore && !disabled}
103
+ <BareInput
104
+ type='text'
105
+ class='flex-1 min-w-[100px] bg-transparent border-none outline-none'
106
+ bind:value={inputValue}
107
+ bind:inputRef={inputElement}
108
+ placeholder={displayPlaceholder}
109
+ {disabled}
110
+ onkeydown={handleKeydown}
111
+ onblur={handleBlur}
112
+ />
113
+ {/if}
114
+ </div>
110
115
  </div>
@@ -0,0 +1,18 @@
1
+ import type { Size } from '../types.js';
2
+ interface FormControlSizeClasses {
3
+ /** 固定高度,适用于单行控件 */
4
+ height: string;
5
+ /** 最小高度,适用于内容可换行的控件 */
6
+ minHeight: string;
7
+ /** 水平内边距与字号 */
8
+ spacing: string;
9
+ /** 固定高度、水平内边距与字号的完整组合 */
10
+ control: string;
11
+ }
12
+ /**
13
+ * 获取输入类控件的统一尺寸类名。
14
+ *
15
+ * 仅供组件内部复用,确保 Input、Select 与复合输入控件使用同一盒模型。
16
+ */
17
+ export declare function getFormControlSizeClasses(size: Size): FormControlSizeClasses;
18
+ export {};
@@ -0,0 +1,18 @@
1
+ const FORM_CONTROL_SIZE_CLASSES = {
2
+ 'xs': { height: 'h-8', minHeight: 'min-h-8', spacing: 'px-2.5 text-xs', control: 'h-8 px-2.5 text-xs' },
3
+ 'sm': { height: 'h-9', minHeight: 'min-h-9', spacing: 'px-3 text-sm', control: 'h-9 px-3 text-sm' },
4
+ 'md': { height: 'h-10', minHeight: 'min-h-10', spacing: 'px-3 text-sm', control: 'h-10 px-3 text-sm' },
5
+ 'lg': { height: 'h-12', minHeight: 'min-h-12', spacing: 'px-4 text-base', control: 'h-12 px-4 text-base' },
6
+ 'xl': { height: 'h-14', minHeight: 'min-h-14', spacing: 'px-4 text-lg', control: 'h-14 px-4 text-lg' },
7
+ '2xl': { height: 'h-14', minHeight: 'min-h-14', spacing: 'px-4 text-lg', control: 'h-14 px-4 text-lg' },
8
+ '3xl': { height: 'h-14', minHeight: 'min-h-14', spacing: 'px-4 text-lg', control: 'h-14 px-4 text-lg' },
9
+ '4xl': { height: 'h-14', minHeight: 'min-h-14', spacing: 'px-4 text-lg', control: 'h-14 px-4 text-lg' },
10
+ };
11
+ /**
12
+ * 获取输入类控件的统一尺寸类名。
13
+ *
14
+ * 仅供组件内部复用,确保 Input、Select 与复合输入控件使用同一盒模型。
15
+ */
16
+ export function getFormControlSizeClasses(size) {
17
+ return FORM_CONTROL_SIZE_CLASSES[size];
18
+ }
@@ -5,6 +5,7 @@
5
5
  <script lang='ts'>
6
6
  import type { DataAttributes, InputProps } from '../../types.js'
7
7
  import { cn, getDataAttributes } from '../../utils.js'
8
+ import { getFormControlSizeClasses } from '../control-size.js'
8
9
 
9
10
  let {
10
11
  value = $bindable(''),
@@ -39,29 +40,7 @@
39
40
  }: InputProps & DataAttributes = $props()
40
41
 
41
42
  const dataAttributes = $derived(getDataAttributes(restProps))
42
- const containerHeight = $derived(
43
- size === 'xs'
44
- ? 'h-8'
45
- : size === 'sm'
46
- ? 'h-9'
47
- : size === 'lg'
48
- ? 'h-12'
49
- : size === 'xl'
50
- ? 'h-14'
51
- : 'h-10',
52
- )
53
-
54
- const inputSpacingClass = $derived(
55
- size === 'xs'
56
- ? 'px-2.5 text-xs'
57
- : size === 'sm'
58
- ? 'px-3 text-sm'
59
- : size === 'lg'
60
- ? 'px-4 text-base'
61
- : size === 'xl'
62
- ? 'px-4 text-lg'
63
- : 'px-3 text-sm',
64
- )
43
+ const sizeClasses = $derived(getFormControlSizeClasses(size))
65
44
 
66
45
  const inputTypeClass = $derived(
67
46
  type === 'number'
@@ -72,7 +51,7 @@
72
51
  const containerClass = $derived(
73
52
  cn(
74
53
  'flex items-center w-full rounded-lg border bg-base-100',
75
- containerHeight,
54
+ sizeClasses.height,
76
55
  error
77
56
  ? 'border-error/60 focus-within:ring-2 focus-within:ring-error/15'
78
57
  : 'border-base-content/15 focus-within:border-primary/50 focus-within:ring-2 focus-within:ring-primary/10',
@@ -136,7 +115,7 @@
136
115
  autocomplete={autocomplete as HTMLInputElement['autocomplete']}
137
116
  class={cn(
138
117
  'flex-1 h-full bg-transparent border-none outline-none placeholder:text-base-content/35',
139
- inputSpacingClass,
118
+ sizeClasses.spacing,
140
119
  inputTypeClass,
141
120
  )}
142
121
  bind:value
@@ -11,6 +11,7 @@
11
11
  <script lang='ts' generics="T = string">
12
12
  import type { DataAttributes, SelectProps } from '../../types.js'
13
13
  import { cn, getDataAttributes, portal } from '../../utils.js'
14
+ import { getFormControlSizeClasses } from '../control-size.js'
14
15
 
15
16
  let {
16
17
  value = $bindable<T>(),
@@ -39,14 +40,7 @@
39
40
  // 下拉层定位样式(portal 到 body,用 fixed 逃逸 overflow/stacking)
40
41
  let dropdownStyle = $state('')
41
42
 
42
- // 尺寸映射(与 Input 保持一致)
43
- const sizeClasses: Record<string, string> = {
44
- xs: 'h-8 text-xs px-2.5',
45
- sm: 'h-9 text-sm px-3',
46
- md: 'h-10 text-sm px-3',
47
- lg: 'h-12 text-base px-4',
48
- xl: 'h-14 text-lg px-4',
49
- }
43
+ const sizeClasses = $derived(getFormControlSizeClasses(size))
50
44
 
51
45
  // 选项文字尺寸
52
46
  const optionTextClass = $derived(
@@ -81,7 +75,7 @@
81
75
  const wrapperClass = $derived(
82
76
  cn(
83
77
  'relative flex w-full min-w-0 items-center rounded-lg border bg-base-100 cursor-pointer',
84
- sizeClasses[size] || sizeClasses.md,
78
+ sizeClasses.control,
85
79
  error
86
80
  ? 'border-error/60 focus-within:ring-2 focus-within:ring-error/15'
87
81
  : isDropdownOpen
@@ -270,7 +264,7 @@
270
264
  {/if}
271
265
 
272
266
  <!-- 右侧图标区域 -->
273
- <div class='flex items-center pr-2 shrink-0'>
267
+ <div class='flex items-center shrink-0'>
274
268
  {#if showClear}
275
269
  <button
276
270
  type='button'