通用组件

@udhold/udhold-ui 通用组件参考:消息提示、确认弹窗、下拉框、快捷键录制、滑杆、详情面板与自适应图标。

@udhold/udhold-ui 是官方共享组件库,随官方插件工程仓库分发(workspace:* 引用,见快速上手)。组件按需 import,没有全局注册,样式与令牌体系一体。

引入方式

// 组件
import { Message, ConfirmDialog, Dropdown, Slider } from '@udhold/udhold-ui/components/common'
// 或分别引:'@udhold/udhold-ui/components/Message'
// 组合式函数与工具
import { useMessage } from '@udhold/udhold-ui/components/common'
import { useColorScheme } from '@udhold/udhold-ui/composables'

Message:全局消息提示

挂载一次,全局调用。 根组件里挂容器(useMessage() 返回的响应式状态接给组件),之后任何地方 useMessage() 直接弹消息:

<script setup lang="ts">
// App.vue —— 挂载容器
import { Message, ConfirmDialog, useMessage } from '@udhold/udhold-ui/components/common'
const { messageState, handleClose, handleAction, confirmState, handleConfirm, handleCancel } = useMessage()
</script>

<template>
  <div id="app"><!-- 页面内容 --></div>
  <Message :items="messageState" @close="handleClose" @action-click="handleAction" />
</template>
// 任何业务组件里
import { useMessage } from '@udhold/udhold-ui/components/common'

const message = useMessage()
message.success('已复制颜色 #2f6fec')
message.error('导出失败:文件被占用')
message.warning('列表已过期,正在刷新')
message.info('已切换到紧凑模式')
参数说明
typesuccess / error / warning / info / primary,对应语义前置圆点
duration停留时长,默认 3000ms
positiontop / bottom

ConfirmDialog:确认弹窗

与 useMessage() 同源,命令式调用,返回 Promise——不用自己管理弹窗状态:

const { confirm, confirmWithExtra, alert } = useMessage()

// 二选一确认
const ok: boolean = await confirm({
  title: '删除记录',
  message: '删除后不可恢复,确定删除这 3 条记录吗?',
  type: 'danger',          // info / warning / danger,控制确认按钮风格
  confirmText: '删除'
})
if (ok) { /* 执行删除 */ }

// 带附加复选项(如「同时删除云端数据」)
const result = await confirmWithExtra({
  title: '卸载插件',
  message: '将删除插件及其全部数据。',
  type: 'danger',
  extra: [{ id: 'keepData', message: '保留插件数据', defaultChecked: false }]
})
// result.confirmed: boolean, result.extra: { keepData: boolean }

// 纯提示(单按钮)
await alert({ title: '导入完成', message: '共导入 128 条记录。' })

容器同样在根组件挂一次:<ConfirmDialog v-model:visible="confirmState.visible" ... />,模板见上面 Message 的 App.vue 示例。

原生 select 的样式化封装(弹出面板跟随系统明暗):

<script setup lang="ts">
import { ref } from 'vue'
import { Dropdown } from '@udhold/udhold-ui/components/common'

const sort = ref('time')
const options = [
  { label: '按时间排序', value: 'time' },
  { label: '按名称排序', value: 'name' }
]
</script>

<template>
  <Dropdown v-model="sort" :options="options" placeholder="选择排序方式" />
</template>

HotkeyInput:快捷键录制

点击进入录制态,按下组合键即完成录入,支持修饰键组合(含 400ms 内双击同一修饰键,如 Ctrl+Ctrl)与 F1–F12:

<script setup lang="ts">
import { ref } from 'vue'
import { HotkeyInput } from '@udhold/udhold-ui/components/common'

const hotkey = ref('Ctrl+Alt+P')
</script>

<template>
  <HotkeyInput v-model="hotkey" placeholder="点击录制快捷键" />
</template>

优先走宿主后端录制(结果与全局快捷键注册系统一致),宿主不支持时自动回退前端按键监听;不支持的按键会以 toast 提示。

Slider:滑杆

<Slider v-model="opacity" :min="30" :max="100" :step="5" :formatter="v => v + '%'" />

轨道已按主色渐变渲染,无需额外样式。

DetailPanel:二级详情面板

覆盖在内容区上方的二级页面(无遮罩、带滑入过渡),配「返回」顶栏——列表页点进详情页的标准形态:

<script setup lang="ts">
import { ref } from 'vue'
import { DetailPanel } from '@udhold/udhold-ui/components/common'
const detailId = ref<string | null>(null)
</script>

<template>
  <Transition name="slide">
    <DetailPanel v-if="detailId" :title="'详情 #' + detailId" @back="detailId = null">
      <template #header-right>
        <button class="icon-btn"><span class="i-z-copy w-4 h-4" /></button>
      </template>
      <!-- 详情内容 -->
    </DetailPanel>
  </Transition>
</template>

组件自带 slide / slide-reverse 过渡类,供 <Transition> 做一级↔二级切换动画。

DetailPanel 内部使用 i-z-back 图标——你的工程图标集里必须有 back.svg(见图标体系),否则返回按钮空白。

AdaptiveIcon:自适应位图图标

位图 logo 在暗色模式下会隐形的痛点,交给它处理:自动分析图片主色,需要时反色:

<AdaptiveIcon :src="provider.logo" alt="服务商图标" class="w-5 h-5" />

懒分析(进入视口前 100px 才开始),forceAdaptive 属性可跳过检测强制暗色反色。

工具函数

@udhold/udhold-ui/utils 里几个高频工具:

函数用途
setupThemeSync()主题联动总入口(主题与明暗模式)
isDarkMode()同步判断当前是否暗色
weightedSearch(items, query, fields)多字段加权搜索:fields 里给每个字段配权重,命中累加按分数排序,做插件内列表过滤很好用
setupPlatformClass()给 html 加 os-windows / os-mac / os-linux 类,CSS 里做平台差异适配
import { weightedSearch } from '@udhold/udhold-ui/utils'

const result = weightedSearch(commands, keyword, [
  { value: c => c.name, weight: 3 },
  { value: c => c.description, weight: 1 }
])

更高层的场景组件(加载态、搜索列表、代码块、侧边导航)看下一篇场景组件。