@h-ai/ui
v0.1.0-alpha.10
Published
Hai Framework UI component library for Svelte 5 Runes.
Downloads
417
Readme
@h-ai/ui
基于 Svelte 5 Runes 的多端 UI 组件库,采用 DaisyUI v5 + Tailwind CSS v4 样式 + Bits UI v2 headless 交互,内置 i18n(zh-CN / en-US),支持 32+ 主题。
安装
npm install @h-ai/ui依赖 @h-ai/core(会自动安装)。
快速开始
1. 配置 svelte.config.js
import { autoImportHaiUi } from '@h-ai/ui/auto-import'
import adapter from '@sveltejs/adapter-auto'
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [autoImportHaiUi(), vitePreprocess()],
compilerOptions: { runes: true },
kit: { adapter: adapter() },
}
export default config2. 配置 vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [sveltekit(), tailwindcss()],
optimizeDeps: { exclude: ['bits-ui'] },
ssr: { noExternal: [/@h-ai\//] },
})3. 配置 src/app.css
@import 'tailwindcss';
@import '@h-ai/ui/styles/global.css';
@import '@h-ai/ui/styles/theme.css';
@source "../node_modules/@h-ai/ui/dist/**/*.{svelte,ts}";
@plugin "daisyui" {
themes: light --default, dark --prefersdark, cupcake, emerald, corporate, nord, dracula, night;
}
/* 图标(可选) */
@plugin "@iconify/tailwind4" {
prefixes: tabler;
}
@source让 TailwindCSS 扫描@h-ai/ui组件中使用的 class 名,否则组件样式会丢失。
4. 使用组件
<script>
import { Button, Input, Card } from '@h-ai/ui'
</script>
<Card title="示例表单">
<Input placeholder="请输入用户名" />
<Button variant="primary" onclick={handleSubmit}>提交</Button>
</Card>启用自动导入后可直接在模板中使用,无需逐个 import:
<!-- 无需 import { Button } from '@h-ai/ui' -->
<Button variant="primary">提交</Button>组件架构
组件按三层划分(primitives → compounds → scenes):
components/
├── primitives/ # 原子组件(不可再分的基础 UI 单元)
├── compounds/ # 组合组件(由原子组件 + Bits UI headless 组合而成)
└── scenes/ # 场景组件(面向具体业务场景的完整 UI 流程)
├── app/ # 应用级(设置/反馈/主题/语言切换)
├── iam/ # 身份认证
├── storage/ # 存储管理
└── crypto/ # 加密展示组件清单
原子组件 Primitives(21 个)
| 组件 | 描述 | 主要属性 |
| ---------------- | ------------ | ------------------------------------------------------------------ |
| Button | 按钮 | variant, size, loading, disabled, outline, circle |
| IconButton | 图标按钮 | icon: string \| Snippet, variant, size, tooltip, loading |
| BareButton | 无样式按钮 | class, ariaLabel, role, tabindex |
| Input | 输入框 | type, value, size, error, validationMessage |
| BareInput | 无样式输入框 | type, class, accept, multiple |
| Textarea | 文本域 | value, rows, size, autoResize, error |
| Select | 下拉选择 | options, value, placeholder, size |
| Checkbox | 复选框 | checked, label, size, indeterminate |
| Switch | 开关 | checked, label, size |
| Radio | 单选组 | options, value, direction, size |
| ToggleCheckbox | 原生开关输入 | checked, name, onchange |
| ToggleInput | 原生切换输入 | checked, name |
| ToggleRadio | 原生单选输入 | checked, name, onchange |
| Range | 滑块 | value, min, max, step |
| Rating | 评分 | value, max |
| Badge | 徽章 | variant, size, outline |
| Avatar | 头像 | src, name, size, shape, ring |
| Tag | 标签 | text, variant, size, closable |
| Spinner | 加载动画 | size, variant |
| Progress | 进度条 | value, max, variant, striped, animated |
组合组件 Compounds(25 个)
表单
| 组件 | 描述 | 主要属性 |
| ----------- | -------- | -------------------------------------------- |
| Form | 表单容器 | loading, disabled, onsubmit |
| FormField | 表单字段 | label, error, hint, required |
| TagInput | 标签输入 | tags, maxTags, allowDuplicates, size |
反馈
| 组件 | 描述 | 主要属性 |
| ---------------- | -------- | --------------------------------- |
| Alert | 警告框 | variant, title, dismissible |
| ToastContainer | 通知容器 | 全局放置,配合 toast 单例使用 |
弹层
| 组件 | 描述 | 主要属性 |
| --------- | ------ | ------------------------------------------------------- |
| Modal | 模态框 | open, title, size, closeOnBackdrop, showClose |
| Drawer | 抽屉 | open, position, title, size |
| Confirm | 确认框 | open, title, message, variant, onconfirm |
| Popover | 弹出层 | open, position, trigger, offset |
数据展示
| 组件 | 描述 | 主要属性 |
| ----------- | -------- | ---------------------------------------- |
| Card | 卡片容器 | title, bordered, shadow, padding |
| DataTable | 数据表格 | data, columns, keyField, loading |
| Accordion | 手风琴 | items: AccordionItem[] |
| Timeline | 时间线 | items: TimelineItem[] |
Bits UI headless 交互
| 组件 | 描述 | 主要属性 |
| ------------ | --------------------------- | --------------------------------------------------- |
| Combobox | 可搜索下拉选择(单选/多选) | options, value, multiple, placeholder |
| Calendar | 独立日历 | value: DateValue, minValue, maxValue |
| DatePicker | 日期输入+弹出 | value: DateValue, minValue, maxValue, error |
日期值使用
@internationalized/date的DateValue/CalendarDate类型。
导航
| 组件 | 描述 | 主要属性 |
| ------------ | -------- | -------------------------------------------- |
| Tabs | 标签页 | items, active, type, size |
| Pagination | 分页 | page, total, pageSize, showTotal |
| Breadcrumb | 面包屑 | items, separator |
| Steps | 步骤条 | items, current, direction, clickable |
| Dropdown | 下拉菜单 | items, trigger, position |
| Tooltip | 提示 | content, position, delay |
状态占位
| 组件 | 描述 | 主要属性 |
| ---------- | ------ | ------------------------------------- |
| Skeleton | 骨架屏 | variant, width, height, count |
| Empty | 空状态 | title, description, icon |
| Result | 结果页 | status, title, description |
页面级
| 组件 | 描述 | 主要属性 |
| ------------ | -------- | ------------------------------------------- |
| PageHeader | 页面头部 | title, description,支持 actions 插槽 |
场景组件 Scenes(19 个)
App 应用级(5 个)
| 组件 | 描述 | 主要属性 |
| ---------------- | ---------------- | ------------------ |
| FeedbackModal | 反馈模态框 | open, onsubmit |
| SettingsModal | 设置模态框 | open, onclose |
| LanguageSwitch | 语言切换 | 无需 Props |
| ThemeSelector | 完整主题选择面板 | 无需 Props |
| ThemeToggle | 明/暗主题切换 | 无需 Props |
IAM 身份认证(7 个)
| 组件 | 描述 | 主要属性 |
| -------------------- | ---------- | ----------------------------------------------------- |
| LoginForm | 登录表单 | loading, errors, showRememberMe, onsubmit |
| RegisterForm | 注册表单 | loading, errors, fields, onsubmit |
| ForgotPasswordForm | 忘记密码 | mode, loading, errors, onsubmit |
| ResetPasswordForm | 重置密码 | loading, errors, showCode, onsubmit |
| ChangePasswordForm | 修改密码 | loading, errors, requireOldPassword, onsubmit |
| PasswordInput | 密码输入框 | value, showToggle, showStrength, minLength |
| UserProfile | 用户资料 | user, editable, fields, onsubmit |
Storage 存储(4 个)
| 组件 | 描述 | 主要属性 |
| -------------- | -------- | -------------------------------------------------------- |
| FileUpload | 文件上传 | accept, maxSize, maxFiles, multiple, uploadUrl |
| ImageUpload | 图片上传 | value, accept, maxSize, aspectRatio |
| AvatarUpload | 头像上传 | value, size, maxSize, fallback |
| FileList | 文件列表 | files, layout, showDelete, showDownload |
Crypto 加密展示(3 个)
| 组件 | 描述 | 主要属性 |
| ------------------ | -------- | ------------------------------------------------------- |
| EncryptedInput | 加密输入 | value, encryptedValue, algorithm, showEncrypted |
| HashDisplay | 哈希展示 | value, algorithm, copyable, truncate |
| SignatureDisplay | 签名展示 | signature, publicKey, algorithm, verified |
使用示例
Toast 通知
<script>
import { toast, ToastContainer } from '@h-ai/ui'
function notify() {
toast.success('操作成功')
toast.error('操作失败')
toast.warning('请注意')
toast.info('提示信息', 5000) // 自定义持续时间
}
</script>
<button onclick={notify}>通知</button>
<ToastContainer />典型 CRUD 页面
<script>
import {
PageHeader, Card, DataTable, Button,
Modal, Input, Select, toast, ToastContainer,
} from '@h-ai/ui'
let items = $state([])
let showModal = $state(false)
let loading = $state(false)
let formData = $state({ name: '', type: '' })
const columns = [
{ key: 'name', label: '名称' },
{ key: 'type', label: '类型' },
{ key: 'createdAt', label: '创建时间' },
]
async function handleCreate() {
loading = true
try {
await fetch('/api/items', { method: 'POST', body: JSON.stringify(formData) })
showModal = false
toast.success('创建成功')
} finally {
loading = false
}
}
</script>
<PageHeader title="项目管理" description="管理所有项目">
{#snippet actions()}
<Button onclick={() => showModal = true}>新建</Button>
{/snippet}
</PageHeader>
<Card>
<DataTable data={items} {columns} keyField="id" {loading}>
{#snippet actions(item)}
<Button size="xs">编辑</Button>
<Button size="xs" variant="error">删除</Button>
{/snippet}
</DataTable>
</Card>
<Modal bind:open={showModal} title="新建项目">
<form onsubmit={(e) => { e.preventDefault(); handleCreate() }} class="space-y-4">
<Input placeholder="名称" bind:value={formData.name} required />
<Select
placeholder="选择类型"
bind:value={formData.type}
options={[
{ value: 'a', label: '类型 A' },
{ value: 'b', label: '类型 B' },
]}
/>
</form>
{#snippet footer()}
<Button variant="ghost" onclick={() => showModal = false}>取消</Button>
<Button {loading} onclick={handleCreate}>创建</Button>
{/snippet}
</Modal>
<ToastContainer />登录页面
<script>
import { LoginForm } from '@h-ai/ui'
let loading = $state(false)
let errors = $state({})
async function handleLogin(data) {
loading = true
errors = {}
try {
await fetch('/api/login', { method: 'POST', body: JSON.stringify(data) })
} catch {
errors = { general: '登录失败,请检查用户名和密码' }
} finally {
loading = false
}
}
</script>
<!-- 场景组件内置 i18n,无需传入翻译 props -->
<LoginForm {loading} {errors} onsubmit={handleLogin} showRegisterLink />PasswordInput 受控模式
<script>
import { PasswordInput } from '@h-ai/ui'
let password = $state('')
</script>
<PasswordInput
value={password}
oninput={(e) => { password = e.currentTarget.value }}
placeholder="请输入密码"
showStrength
/>样式依赖
组件基于 TailwindCSS v4 + DaisyUI。应用层 app.css 需要以下配置:
/* 必须 */
@import 'tailwindcss';
@import '@h-ai/ui/styles/global.css'; /* 基础重置、滚动条、焦点样式 */
@import '@h-ai/ui/styles/theme.css'; /* Tailwind v4 @theme Token(品牌色/阴影/动效) */
@source "../node_modules/@h-ai/ui/dist/**/*.{svelte,ts}";
/* 移动端项目追加(可选) */
@import '@h-ai/ui/styles/design-tokens.css'; /* CSS 自定义属性 */
@import '@h-ai/ui/styles/mobile.css'; /* 安全区域/触摸优化 */
/* DaisyUI 主题 */
@plugin "daisyui" {
themes: light --default, dark --prefersdark, cupcake, emerald, corporate, nord, dracula, night;
}global.css:基础 HTML 重置、滚动条美化、表单焦点环theme.css:Tailwind v4@theme块,包含品牌色、阴影层级、动效曲线、字体特性design-tokens.css:CSS 自定义属性(间距/圆角/z-index/过渡),移动端推荐mobile.css:安全区域 padding、momentum 滚动、虚拟键盘适配
图标
组件使用 Iconify (Tabler Icons):
npm install -D @iconify/tailwind4 @iconify-json/tabler/* app.css 中追加 */
@plugin "@iconify/tailwind4" {
prefixes: tabler;
}主题切换
使用内置的主题工具函数管理 32 个 DaisyUI 主题:
import {
applyTheme, // 应用主题(自动持久化到 localStorage)
getCurrentTheme, // 获取当前主题
getThemeInitScript, // 防闪烁脚本(放在 app.html <head> 中)
isDarkTheme, // 检查是否暗色主题
THEME_GROUPS, // 按亮色/暗色分组
THEMES, // ThemeInfo[] — 全部 32 个主题元数据
} from '@h-ai/ui'在 app.html 中添加防闪烁脚本:
<head>
<script>
{@html getThemeInitScript()}
</script>
</head>国际化 (i18n)
@h-ai/ui 采用组件内置翻译模式:
- 场景组件(
scenes/)内置中英文翻译(zh-CN / en-US),开箱即用 - 组件自动响应全局 locale 变化(通过
@h-ai/core同步) - 应用层只需处理页面级文本,组件内部文本由 @h-ai/ui 统一管理
- 如需覆盖特定文本,通过
submitText、labels等 props 传入
createLocaleStore
用于客户端 locale 状态管理,自动同步到 @h-ai/core 全局 locale 管理器:
<script>
import { createLocaleStore, setGlobalLocale } from '@h-ai/ui'
import { setLocale } from '$lib/paraglide/runtime'
const localeStore = createLocaleStore()
function changeLocale(code) {
localeStore.set(code) // 更新 UI store + 同步到 @h-ai/core
setLocale(code) // 同步到 Paraglide(应用层)
}
</script>
<select value={localeStore.current} onchange={(e) => changeLocale(e.currentTarget.value)}>
{#each localeStore.supported as l}
<option value={l.code}>{l.label}</option>
{/each}
</select>导出的 i18n 工具
import {
createLocaleStore, // Svelte 响应式 locale store
DEFAULT_LOCALE, // 默认 locale: 'zh-CN'
DEFAULT_LOCALES, // 支持的 locale 列表
detectBrowserLocale, // 检测浏览器语言
getGlobalLocale, // 获取当前全局 locale
interpolate, // 字符串插值(如 "Hello {name}")
isLocaleSupported, // 检查 locale 是否支持
resolveLocale, // 解析 locale(支持回退)
setGlobalLocale, // 设置全局 locale(同步 @h-ai/core)
} from '@h-ai/ui'其他导出
// 类型
import type { ButtonProps, InputProps, ModalProps } from '@h-ai/ui'// 样式工具
import { cn, generateId, getSizeClass, getVariantClass } from '@h-ai/ui'// Toast 单例
import { toast } from '@h-ai/ui'