@lovince / ui-vue
可访问的,无样式的Vue 3组件为Lovince UI。每个组件都是
状态机来自 @lovince/ui-headless;它的浏览器
效果贯穿始终 @lovince/ui-dom. 这个套餐订阅
机器,输入道具,并呈现什么 connect() 的回报。它不存在
它自己的行为。
状态:
0.5.0、实验。 API之前可能会更改1.0.
bun add @lovince/ui-vue
需要v3.5 +(用于ssr稳定) useId). 包中没有CSS。风格
它与类和 data-* 状态属性,或使用
@lovince/themes 令牌。
每个组件导出都带有 Lv 前缀(LvButton, LvDialogRoot),所以
名称永远不会与您自己的组件或本地元素冲突。
组件
| 集团 | 组件 | 部分 |
|---|---|---|
| 原语 | 文本,标题,标签,链接,代码,Kbd,框,对比度,视觉隐藏,分隔符 | |
| 图标 | LvIcon,从分离 @lovince/ui-vue/icon 条目 | |
| 信息披露 | 信息披露 | LvDisclosureRoot, LvDisclosureTrigger, LvDisclosureContent |
| 手风琴 | LvAccordionRoot, LvAccordionItem, LvAccordionHeader, LvAccordionTrigger, LvAccordionContent | |
| 选项卡 | LvTabsRoot, LvTabsList, LvTabsTrigger, LvTabsContent | |
| 覆盖 | 对话框 | LvDialogRoot, LvDialogTrigger, LvDialogPortal, LvDialogOverlay, LvDialogContent, LvDialogTitle, LvDialogDescription, LvDialogClose |
| Lightbox | LvLightboxRoot, LvLightboxTrigger, LvLightboxPortal, LvLightboxOverlay, LvLightboxContent, LvLightboxTitle, LvLightboxItem, LvLightboxPrevious, LvLightboxNext, LvLightboxCounter, LvLightboxClose | |
| 弹出窗口 | LvPopoverRoot, LvPopoverTrigger, LvPopoverAnchor, LvPopoverPortal, LvPopoverContent, LvPopoverClose | |
| 工具提示 | LvTooltipRoot, LvTooltipTrigger, LvTooltipPortal, LvTooltipContent | |
| 悬停卡 | LvHoverCardRoot, LvHoverCardTrigger, LvHoverCardPortal, LvHoverCardContent | |
| 菜单 | LvDropdownMenuRoot, LvDropdownMenuTrigger, LvDropdownMenuContent, LvDropdownMenuItem, LvDropdownMenuCheckboxItem, LvDropdownMenuRadioGroup, LvDropdownMenuRadioItem, LvDropdownMenuItemIndicator, LvDropdownMenuLabel, LvDropdownMenuGroup, LvDropdownMenuSeparator, LvContextMenuTrigger | |
| 导航菜单 | LvNavigationMenuRoot, LvNavigationMenuList, LvNavigationMenuItem, LvNavigationMenuTrigger, LvNavigationMenuContent, LvNavigationMenuLink | |
| 烤面包 | LvToastViewport, LvToastRoot, LvToastTitle, LvToastDescription, LvToastAction, LvToastClose,再加上 toast() | |
| 选择 | 复选框,切换 | LvCheckboxRoot, LvCheckboxIndicator, LvSwitchRoot, LvSwitchThumb |
| 广播组 | LvRadioGroupRoot, LvRadioGroupItem, LvRadioGroupIndicator | |
| 切换,切换组 | LvToggleRoot, LvToggleGroupRoot, LvToggleGroupItem | |
| 选择 | LvSelectRoot, LvSelectTrigger, LvSelectValue, LvSelectContent, LvSelectItem, LvSelectItemText, LvSelectItemIndicator, LvSelectGroup, LvSelectLabel, LvSelectSeparator | |
| 组合框 | LvComboboxRoot, LvComboboxAnchor, LvComboboxInput, LvComboboxTrigger, LvComboboxClear, LvComboboxContent, LvComboboxItem, LvComboboxItemIndicator, LvComboboxEmpty | |
| 命令面板 | LvCommandRoot, LvCommandInput, LvCommandList, LvCommandGroup, LvCommandItem, LvCommandEmpty, LvCommandSeparator | |
| Emoji选择器 | LvEmojiPickerRoot, LvEmojiPickerSearch, LvEmojiPickerList, LvEmojiPickerGroup, LvEmojiPickerItem, LvEmojiPickerNav… | |
| 输入 | 滑块 | LvSliderRoot, LvSliderTrack, LvSliderRange, LvSliderThumb |
| 角滑块 | LvAngleSliderRoot, LvAngleSliderTrack, LvAngleSliderMarkers, LvAngleSliderIndicator, LvAngleSliderThumb, LvAngleSliderValue | |
| 数域 | LvNumberFieldRoot, LvNumberFieldInput, LvNumberFieldIncrement, LvNumberFieldDecrement | |
| 销的输入 | LvPinInputRoot, LvPinInputInput | |
| 日历 | LvCalendarRoot, LvCalendarHeading, LvCalendarPrev, LvCalendarNext, LvCalendarGrid, LvCalendarHeadCell, LvCalendarCell, LvCalendarDay | |
| 形式 | 字段,输入,文本区域,表单,TagsInput, FileUpload, TimeField, PhoneInput | LvFieldRoot, LvFieldLabel, LvTagsInputRoot, LvTagsInputInput, LvTagsInputItem, LvTagsInputRemove, LvFileUploadRoot, LvFileUploadInput, LvFileUploadItem, LvFileUploadRemove, LvTimeFieldRoot, LvTimeFieldInput, LvPhoneInputRoot, LvPhoneInputInput, LvPhoneInputCountrySelect |
| 时钟选择器 | LvClockPickerRoot, LvClockPickerViewTrigger, LvClockPickerMeridiem, LvClockPickerDial, LvClockPickerHand | |
| 布局 | ScrollArea | LvScrollAreaRoot, LvScrollAreaViewport, LvScrollAreaScrollbar, LvScrollAreaThumb |
| 分配器 | LvSplitterGroup, LvSplitterPanel, LvSplitterHandle | |
| 树 | LvTreeRoot, LvTreeItem, LvTreeGroup | |
| 旋转木马 | LvCarouselRoot, LvCarouselViewport, LvCarouselSlide, LvCarouselPrevious, LvCarouselNext, LvCarouselIndicators, LvCarouselIndicator | |
| 可分类的 | LvSortableRoot, LvSortableItem, LvSortableHandle | |
| 部分 | LvSectionRoot, LvSectionHeader, LvSectionEyebrow, LvSectionTitle, LvSectionDescription, LvSectionContent | |
| 显示 | 《阿凡达》,进步 | LvAvatarRoot, LvAvatarImage, LvAvatarFallback, LvProgressRoot, LvProgressIndicator |
| 计,倒计时 | LvGauge, LvCountdownRoot, LvCountdownSegment | |
| 表格 | LvTableContainer, LvTableRoot, LvTableCaption, LvTableHeader, LvTableBody, LvTableFooter, LvTableRow, LvTableHead, LvTableCell,再加上 LvDataTable |
原语
这些原语提供了语义HTML和稳定的样式挂钩,而不会强加于人
CSS。 LvText 和 LvHeading 公开 data-text-role 匹配排版
角色 @lovince/tokens;标题级别控制语义独立于
视觉的大小。
<script setup lang="ts">
import { LvAspectRatio, LvCode, LvHeading, LvKbd, LvLabel, LvLink, LvSeparator, LvText, LvVisuallyHidden } from '@lovince/ui-vue'
</script>
<template>
<LvHeading :level="1" size="display-md">Workspace</LvHeading>
<LvText variant="body-md">Manage projects and members.</LvText>
<LvLabel for="query">Search</LvLabel>
<LvLink href="/guide">Read the guide</LvLink>
<LvCode>bun test</LvCode>
<LvKbd>Ctrl+K</LvKbd>
<LvAspectRatio :ratio="16 / 9">
<img src="/product.webp" alt="Product detail" />
</LvAspectRatio>
<LvVisuallyHidden>Search projects</LvVisuallyHidden>
<LvSeparator :decorative="false" />
</template>
LvBox, LvAspectRatio, LvText, LvHeading, LvLabel, LvLink, LvCode, LvKbd,
LvVisuallyHidden 支持 as 和 asChild. LvAspectRatio 默认为1:1
框架;集 ratio 到一个正有限数,例如 16 / 9 来衡量它的大小
内容区域。 LvLink 默认为锚,并留下导航属性
如 href, target, rel 在来电者的控制之下。 LvCode 和
LvKbd 默认为它们对应的语义元素。当 LvHeading
呈现一个非标题元素,它保持其语义级别
role="heading" 和 aria-level. LvVisuallyHidden 应用最小的内联
剪辑风格需要保持辅助技术的可用性。一个
non-decorative LvSeparator 公开分隔符语义及其方向;
装饰性分隔符隐藏在可访问性树中。
按钮
LvButton 是命名设计决策的部分: variant
(solid, subtle, outline, ghost, danger), size (sm, md, lg,
icon)成为 data-variant 和 data-size,而样式表决定了什么
他们每个人看起来都像。组件所拥有的是手写的标记
按钮出错了。
<script setup lang="ts">
import { LvButton } from '@lovince/ui-vue'
</script>
<template>
<LvButton @click="save">Save</LvButton>
<LvButton type="submit" variant="solid" size="lg" :loading="saving">Save</LvButton>
<LvButton as="a" href="/settings" variant="ghost" size="sm">Settings</LvButton>
<LvButton :disabled="!valid" variant="outline">Publish</LvButton>
</template>
type默认为button,因此表单中的按钮永远不会提交 事故;问......为......submit或者reset明确。disabled当元素为实元素时,设置native属性button,aria-disabled当它不是,因为锚不能被禁用。loading集合aria-busy并将控件保持在TAB顺序中——这是一个请求 从键盘开始,在吞咽时保持键盘可见 单击以使处理程序不能触发两次。- 这两个状态也显示为
data-disabled和data-loading,两者都没有 运行onClick这是给定的。与asChild元素是你的,点击 处理包括;状态属性仍然到达。
图标
LvIcon 从中绘制一个象形符号 @lovince/icons 在注册表的共享24单元上
画布。它是它自己的条目,因为icon注册表是一个可选的peer:
进口 @lovince/ui-vue 没有加载图标数据,一个应用程序带来了自己的
icon不需要额外的东西。
<script setup lang="ts">
import { LvIcon } from '@lovince/ui-vue/icon'
</script>
<template>
<LvIcon name="arrowRight" />
<LvIcon name="success" :size="16" :stroke-width="1.5" label="Completed" />
</template>
图标是装饰性的 aria-hidden="true" -除非给出 label,
也就是说 role="img" 用那个通俗易懂的名字。 absoluteStrokeWidth
使渲染的描边厚度恒定为 size 生长; fill 取0到
1用于部分洗涤; rotate 和 flip 围绕画布中心转动。大小和
笔画退回到注册表自己的默认值,并且未知 name 呈现一个
空框而不是破坏布局。
形式
LvFieldRoot 提供一个稳定的输入id,并连接标签、描述和
误差为 LvInput 或者 LvTextarea. 描述和错误副本可以作为参数传递
道具或命名槽。集 invalid 暴露一个错误槽,或通过 error 来
自动将该字段标记为无效。 required 和 disabled 传播
对现场进行控制;每个控件都可以覆盖它们。
<script setup lang="ts">
import { LvFieldLabel, LvFieldRoot, LvForm, LvInput, LvTextarea } from '@lovince/ui-vue'
</script>
<template>
<LvForm @submit.prevent="save">
<LvFieldRoot required description="Use your work email.">
<LvFieldLabel>Email</LvFieldLabel>
<LvInput type="email" name="email" autocomplete="email" />
</LvFieldRoot>
<LvFieldRoot :invalid="Boolean(message)" :error="message">
<LvFieldLabel>Project summary</LvFieldLabel>
<LvTextarea name="summary" />
</LvFieldRoot>
<button type="submit">Save</button>
</LvForm>
</template>
LvInput 和 LvTextarea 支持 modelValue / defaultValue 并发出
update:modelValue. LvTextarea 使用基于内容的字段大小
浏览器支持它,并保留了一个本机 rows 回退。 LvForm 是本地人
表单包装器:浏览器约束验证和提交事件保留在
控制。集 submitting 暴露 aria-busy 和 data-submitting,或者
noValidate 在其他地方处理验证时。
TagsInput 和 FileUpload 公开它们的当前值和被拒绝的条目
通过根节点的默认槽位。他们纯粹的规则和拒绝的理由依然存在
@lovince/ui-headless.
<script setup lang="ts">
import {
LvFileUploadInput,
LvFileUploadItem,
LvFileUploadRemove,
LvFileUploadRoot,
LvTagsInputInput,
LvTagsInputItem,
LvTagsInputRemove,
LvTagsInputRoot,
} from '@lovince/ui-vue'
</script>
<LvTagsInputRoot v-model="emails" :max="5" :validate="isEmail" name="emails">
<LvTagsInputItem v-for="(email, index) in emails" :key="email" :index="index">
{{ email }} <LvTagsInputRemove />
</LvTagsInputItem>
<LvTagsInputInput label="Add email address" />
</LvTagsInputRoot>
<LvFileUploadRoot v-model="files" accept="image/*,.pdf" :max-files="4" :max-size="5000000">
<LvFileUploadInput />
<LvFileUploadItem v-for="(file, index) in files" :key="file.name" :index="index">
<template #default="{ file, size }">
{{ file.name }} ({{ size }}) <LvFileUploadRemove />
</template>
</LvFileUploadItem>
</LvFileUploadRoot>
使用Enter或配置的分隔符创建标签;粘贴separator-delimited
文本被分割,并产生重复、无效和超出限制的值 rejected.
文件选择和删除共享相同的类型、每个文件大小、计数和总数
尺寸检查。 LvFileUploadRoot 发出接受 File[] 值和被拒绝的文件
用他们的理性; LvFileUploadItem 还暴露了kind, extension和localized
大小到它的槽。
TimeField 接受人工输入的时间并进行规范化存储 HH:mm 值。
它验证了可选 min 和 max 模糊或回车键的边界,并曝光
invalid 解析或范围验证失败时。 PhoneInput 格式一个
国家号码模糊,识别支持的国际前缀,还有
发出E.164值。它包含一个国家选择器,并接受一个可选的
自定义国家列表。
<LvTimeFieldRoot v-model="appointment" min="09:00" max="17:00" required name="appointment">
<LvTimeFieldInput label="Appointment time" />
</LvTimeFieldRoot>
<LvPhoneInputRoot v-model="phone" country="KE" name="phone">
<LvPhoneInputCountrySelect />
<LvPhoneInputInput label="Mobile number" />
</LvPhoneInputRoot>
ScrollArea 保持滚动原生,同时暴露自定义,键盘可操作
滚动条的部分。从其容器中调整根的大小,然后渲染viewport和
滚动条/拇指部分在其中。根槽位报告当前溢出
指标;样式跟踪和拇指与他们的 data-scroll-area-* 属性。
视口保持其原生滚动行为和用途 scrollbar-width: none
支持该属性的地方。
<LvScrollAreaRoot class="results">
<LvScrollAreaViewport>
<div v-for="result in results" :key="result.id">{{ result.title }}</div>
</LvScrollAreaViewport>
<LvScrollAreaScrollbar>
<LvScrollAreaThumb />
</LvScrollAreaScrollbar>
</LvScrollAreaRoot>
可组合: useDataTable, useVirtualList, useInView, useScrollEdges,
useActiveSection, useClipboard,再加上下面的积木。
包裹是 sideEffects: false. 只能导入应用程序 LvDialogRoot 船只
没有菜单、选择或表代码,测试强制执行这一点。
共同的约定
as和asChild. 每个部分都是一个合理的元素as去改变它。与asChild,部分呈现你的独生子女, 将其属性和处理程序合并到。- 控制与否。 离开
v-model关闭,组件拥有自己的状态。 把它和你的价值结合起来,就是真理的源泉。每一个被接受的改变 发出,并将模型设置为undefined清除它。 - 你的身份受到尊重。 给任何部分
id和ARIA参考文献 其他地方也一样。 - 退出动画播放。 关闭内容保持安装状态,使用
data-state="closed",直到它的CSS动画结束。没有动画,或者 减少运动,它立即卸载。 - Hydration-safe门户。 只在挂载后覆盖传送,所以服务器和 客户端呈现总是同意。
- 可删除的解雇。 覆盖发出
escapeKeyDown和pointerDownOutside(对话框也focusOutside)。呼叫event.preventDefault()让它们保持开放。
Lovince-specific行为
以下两种行为与Doitrix组件不同:
- 披露内容和选项卡面板留在DOM中 与
hidden而 关闭了,所以在页面中找到aria-controls继续工作。 - Tabs选择第一个启用的选项卡 当没有给出值时,包括during 服务器呈现。
模态对话框也构成了页面的其余部分 inert而不仅仅是专注。
构建块
这个包中的每个组件都是以同样的方式构建的:
const machine = useMachine(dialogMachine, initialContext, {
controlled: { open: () => props.open }, // a v-model, synced in
onChange: (next, previous) => emit(…), // accepted changes, never echoes of props
beforeSend: dismiss.filter, // e.g. cancellable dismissal
})
const api = computed(() => connectDialog(machine.snapshot.value, machine.send))
// h(Primitive, normalizeProps(api.value.contentProps), slots)
useMachine在挂载时启动效果(在服务器上没有),在挂载时停止效果 卸载,保持一个受控值的来源的真理,并提供query那connect通读整页。组件永远不会接触 DOM。normalizeProps转动引擎的中性支柱(onKeyDown)到Vue's (onKeydown). React适配器将在相同的机器上发布自己的适配器。useListEnv以视觉顺序从DOM中读取机器的列表项 导航列表。Primitive,Slot,Portal,usePresence,useIdWatch处理 呈现的问题:as/asChild水合安全的入口,出口动画, 消费者的id。
状态属性
| 属性 | 值 |
|---|---|
data-state | open / closed, checked / unchecked / indeterminate, active / inactive |
data-disabled, data-readonly | 设定时呈现 |
data-orientation | horizontal / vertical |
data-side, data-align | 碰撞处理后,浮动内容放置在哪里 |
浮动内容载体 data-anchor-hidden 当它的锚滚动时
看,又暴露 --lovince-floating-available-height,
--lovince-floating-available-width 和 --lovince-anchor-width. 信息披露
内容公开 --lovince-collapsible-height 和 -width 用于高度动画。
已知的限制
- 定位是引擎自己的(参见
@lovince/ui-headless): 它尊重滚动容器和转换后的祖先,并隐藏内容 谁的锚已经卷走(data-anchor-hidden). 箭头不是内置的。 - 看到
@lovince/ui-dom用于inert滚动锁浏览器警告。
许可证
麻省理工学院