npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@robert-stackflow/oneui

v0.6.42

Published

OneUI React components, application shell and portable visual themes

Readme

@robert-stackflow/oneui

React 组件、应用外壳和两套可互换的主题。无 Electron、React Router、账户 API 或持久化存储依赖。

分栏按钮与嵌套浮层(0.6.40)

SplitButton 保留 items 菜单,支持 label / iconOnly / size / pressed、ghost 外观、受控 open / onOpenChange,以及自定义 panel / panelWidth / portalContainer。主动作与展开区分别响应,自定义面板复用非模态箭头 Popover。图标提示的包裹层不会阻断按钮样式。

ghost 图标按钮及分栏按钮的展开 / 选中态使用主题轻背景;嵌套 Popover 按 Escape 先关闭最内层。保留现有图文动作、禁用状态、Popover 自适应内容宽度和主题能力。

禁用按钮与贡献日历(0.6.38)

IconButton disabled / aria-disabled 使用统一的弱化外观,不再响应 hover 填充。应用按业务边界传入禁用状态,不额外覆盖按钮皮肤。

ContributionCalendar fill 在可用版心中放大网格;source 替换左下角默认日期范围,footer 在分隔线下提供统计等组合内容。调用方复用原生日历的主题、边框、提示和交互,不在外层再套 Card。

菜单滚动边界(0.6.37)

ContextMenu 打开期间会接管滚轮:长菜单仍可在内部滚动,短菜单及边界滚动不会传递到正文或嵌套工作区;关闭后恢复。

底部浮动操作栏(0.6.36)

FloatingActionBar open={selected.length > 0} label="已选记录" container={contentRef} 提供非模态的底部操作区:复用弹层边框、阴影和进退场动效,关闭动画期间保持挂载且不可交互;不会抢走复选框焦点。container 将操作栏对齐到所属内容区域,窄屏自动限制宽度;弹窗内使用所属弹层的 portal。bottom 默认 24,保留安全区域。按钮支持左右方向键、Home/End;计数、业务操作及清除选择由消费方组合。

表格横向滚动区域仅限制横向滚动链,垂直滚轮继续交给外层工作区。

图文操作按钮(0.6.35)

<IconButton label="点赞 12" text={12}><Heart /></IconButton> 将图标和文字/数字放在同一个按钮内,共享 hover、键盘焦点、按下与选中区域。text="回复" / text="分享" 使用相同布局;数字 0 也会显示。不要在按钮外再放计数文字。label 是完整可访问名称及提示,text 是可见内容;省略 text 时保留原图标按钮行为。loading 时文字保留,图标替换为 Spinner。

密码输入(0.6.29)

PasswordField 统一提供显示/隐藏密码操作,在 Edge 中隐藏重复的原生显示按钮。应用无需为该输入框覆盖浏览器伪元素样式。

长表单弹窗(0.6.28)

Dialog 的标题、关闭按钮和 footer 操作保持可见,超高内容在正文内部滚动。将主操作放入 footer,不要在应用侧为弹窗叠加高度、固定定位或滚动样式。闭合的原生弹窗仍保持隐藏,嵌套弹窗沿用统一焦点与进退场规则。

紧凑操作栏与切换按钮(0.6.26)

Popover width="content" arrow scrollable={false} 按内容确定宽度,并限制在视口边距内,适合文本和表格的上下文操作栏。关闭时保持组件挂载并传入 open={false},由 OneUI 完成箭头、进退场和减少动态效果处理。

IconButton variant="ghost" aria-pressed={active} 使用主题选中底色与前景色,保持无描边;不要用 secondary 变体模拟切换选中。

带指向箭头的浮层(0.6.22)

Popover arrow offset={14} 在浮层边缘显示指向 anchor 的小三角,并以该点为原点轻微缩放、位移和淡入淡出。offset 控制浮层边缘与触发区域的距离;默认值保持原有布局。箭头在窗口边缘钳制位置后仍对准触发区域,内容在内部滚动。动效继承主题时长和减少动态效果设置。

IconButton disclosure aria-expanded={open} 自动添加有间距的展开箭头、旋转动效和展开状态;调用方只传主要图标。组合按钮的尺寸与焦点继续由 OneUI 负责。

内容链接与阅读字号(0.6.21)

Link 从根入口或 @robert-stackflow/oneui/Link 导入。默认使用主题链接色;variant="subtle" 继承周围标题或正文的颜色与字体,统一 hover、键盘焦点和 disabled 行为,保留原生链接与新标签打开语义。应用无需单独定义标题链接样式。

Markdown 支持 fontSize={18},正文与相对字号标题共同缩放;不传时保持默认 14 px。有限数值限制在 10–48 px,非有限数值沿用默认值。

可读前景色(0.6.16 候选)

--accent-ink 用于文字、小图标、细标记和焦点;按钮实心填充仍使用 --accent-fill / --accent。极简主题的 ink 随前景色变化,蓝白主题使用相应模式的强调色;自定义强调色混入当前前景色后用于 ink,避免深色模式中的深灰标记或浅色模式中的白色标记不可见。可单独覆盖此变量。徽标、链接、步骤、菜单/单选标记、进度、图表、时间线及信息反馈复用这套颜色。

导航指示线(0.6.15 候选)

indicator 风格的 SideBar 使用当前主题的导航前景色绘制细线,极简深色不再复用深灰强调色。自定义强调色会混入当前前景色,保持浅、深模式中的可辨识度;可通过 --navigation-indicator-color 覆盖。此颜色独立于按钮填充色,几何和滑动动画保持原有行为。

表单与设置的标题层级(0.6.40)

卡片标题为 16px / 600,分组标题及 FormGroup legend 为 14px / 600,字段标签为 13px / 400,辅助说明为 12px。两套主题及深浅色使用同一层级,颜色跟随主题。不要通过加粗所有字段来制造分组,也不要为已经明确的结构重复添加小标题。

Section 支持 headingLevel(2–6,默认 2)和 contentLayout="settings";卡片内分组通常传 headingLevel={3}。普通内容的标题间距为 12px;SettingRow 列表传 settings 以避免标题与设置行内边距叠加。连续 Section 的父容器使用 gap={0},组间距交给 Section,末组无尾距。Card 支持 headingLevel,标题级别独立于视觉字号。规范及主题变量见仓库 docs/form-hierarchy.md。

设置项(0.6.14 候选)

基础 SettingRow 保留自由组合的右侧内容,支持 titleBold(默认 false)、align 和 controlWidth。派生组件复用同一行布局:TextSettingRow、TextAreaSettingRow、SwitchSettingRow、SelectSettingRow,均支持 title、description、divider、titleBold;文本控件支持原生输入属性、ref、hint 和 error,onChange 直接返回文本值,开关返回 boolean。下拉选择继承 Select 的 options/value/onChange 等属性。

<TextSettingRow title="工作区名称" value={name} onChange={setName} />
<TextAreaSettingRow title="个人简介" value={bio} onChange={setBio} rows={3} />
<SwitchSettingRow title="接收通知" checked={enabled} onChange={setEnabled} />
<SelectSettingRow title="默认语言" value={language} onChange={setLanguage} options={languages} />

派生项将标题关联到控件,说明文字并入可访问描述;有宽度设置的输入/选择项在窄屏自动上下排列,多行文本的标题默认顶部对齐。所有组件和 Props 类型可从根入口导入,也提供各自同名子路径。示例入口为 /forms?view=settings。Form / FormField / FormGroup 继续负责可提交表单的布局、分组和校验,不要求用 SettingRow 替代。

提示与对话框(0.6.14 候选)

Dialog、MessageDialog、ConfirmDialog、FormDialog 统一使用浅底 footer、顶部细分割线和靠右的操作按钮。标题与正文左对齐,状态提示用小尺寸语义图标区分,不使用居中大图标布局。Dialog 可传 headerIcon 与 tone="neutral" | "info" | "success" | "warning" | "danger"。MessageDialog 可通过 onAction 为主按钮提供异步操作,closeLabel 设置其文字;等待期间禁止重复提交和关闭,失败时保留内容并显示 Banner,返回 false 可保留弹窗。

Banner 的 soft 使用低对比底色,outline 使用中性细边框,filled 提高底色强度;标题、正文和语义图标分层显示。操作和详情开关位于正文下方的同一行,关闭独立放在右上角。详情开关复用文字按钮,hover 无按钮底色;窄屏操作自然换行,减少动效时仍可完整展开。

阅读与反馈(0.6.13 候选)

TableOfContents 使用 contentRef 发现标题,或接收 {id,label,level?}[]。variant="tree" 使用层级路径、高亮可见标题范围和沿路径移动的定位点;几何只在尺寸变化时测量,滚动由 IntersectionObserver 更新状态。设计参考 Fumadocs TOC。variant="rail" 是独立的沉浸式样式,只标记当前阅读位置,短线 hover 有局部伸展,旁边的卡片使用无层级、无编号的平面目录。短线本身是可点击的原生锚点链接。hoverMode="single" | "nearby" | "all" 控制悬浮卡片展示当前标题与摘要、附近目录或全部目录,previewCount(默认 5)控制附近目录的总条数,depthBasedLength 可按层级改变短线基准长度。显式 items 可提供 description,自动发现时提取标题后的段落摘要。浮层跟随当前 hover 的短线定位,支持自动定位、键盘焦点、Escape、视口翻转及全局滚动条;不会接管正文之外的滚动。

Table、DataTable、TreeTable、TableMarkup 共用 TableAppearance:striped、density="comfortable" | "compact"、hoverable、bordered、stickyHeader。选中行优先于交替行和 hover,层级表格只保留一层外框。

提示横幅主入口改为 Banner,两端应用与示例均使用新名称。支持五种 tone、soft/outline/filled 变体、compact、图标、标题、操作、关闭,以及受控或内部状态的可展开 details。旧的 Alert 仅保留兼容别名,不维护另一套实现。

Toast 默认采用轻叠卡片:最新消息在前,后层仅露出边缘,悬停、键盘聚焦或点击数量按钮后展开;Escape 收起。ToastProvider maxVisible 默认 3,控制收起时露出的卡片层数,展开可访问整组通知。组内按实际高度排列,超出视口时只滚动通知区域,不增加页面滚动条;六个位置均使用受约束的原生顶层浮层。深色与柔和样式的按钮分别保持悬停、按下和键盘焦点对比度。

只有前台可读的消息计时;展开、悬停、聚焦及异步操作暂停计时,恢复后继续剩余时长。notify(message,{id:"task"}) 用同一个 id 原位更新异步任务并重置该消息的时长。createToaster().getSnapshot() 仍返回最新一条,getQueueSnapshot() 返回队列;带 id 的 dismiss/clear 只影响对应消息,无参时作用于全部消息。旧关闭函数不会影响后来的其他消息。独立使用的 Toast 保留原生浮层与已有调用方式。

Markdown

从 @robert-stackflow/oneui/Markdown 导入 <Markdown>{source}</Markdown>。统一渲染 CommonMark/GFM 标题、列表、引用、表格、任务列表、链接、图片、删除线与脚注;代码块带语言标记和复制操作,长代码和表格在各自区域滚动,排版跟随 OneUI 主题。默认省略原始 HTML,保留解析器的 URL 过滤;外部 HTTP 链接打开新标签页,相对链接和文档内锚点保留当前页面跳转。

可通过 className 设置外层布局,components 覆盖单个元素的渲染。每个实例使用独立脚注 ID,允许在同一页面并排展示。基于 [email protected] 和 [email protected],无需应用再配置解析器。示例位于「数据展示 → Markdown」。

高亮主题通过 codeTheme="auto" | "github-light" | "github-dark" | "nord" | "dracula" 选择。语法解析由 lowlight 生成虚拟节点,不注入 HTML;未知语言保留原文。表格直接使用 TableMarkup,可用 tableProps 传入相同的 TableAppearance 选项。标题和脚注 ID 按实例隔离,可直接与 TableOfContents 联动。

导航组件(0.6.11 候选)

SideBar 统一纵向导航,通过 variant="sidebar" | "card" | "indicator" 切换普通侧栏、卡片背景、透明背景加左侧指示线。三种样式共用结构和状态,选中底板保持固定宽度并沿纵向移动,指示线与底板同步。groupHeaderBold(默认 false)控制分组标题整体加粗,单个分组的 headerBold 可覆盖;AppShell 和 SettingsLayout 同样支持整体设置。侧栏和卡片保留组间分隔线;指示线样式默认静态分组。

使用 items/groups、active、onNavigate 和可选 basePath;默认保留真实链接及修饰键打开行为,mode="buttons" 适用于设置等页内切换。项目使用稳定 id 与 path,通过 children 嵌套。expandedIds / defaultExpandedIds / onExpandedChange 控制嵌套展开,collapsedGroupIds / defaultCollapsedGroupIds / onCollapsedGroupsChange 控制分组折叠。组的 collapsible 可覆盖默认行为。

item 的 trailing 可放数字、圆点、Spinner 或自定义组件,布局与导航按钮、展开按钮分开,支持独立交互。分组的 trailing 也接受 ({collapsed, active}) => ReactNode;例如 trailing: ({collapsed}) => collapsed ? <Badge>4</Badge> : null 仅在折叠时显示数量,不自动插入圆点。

分组和嵌套通过同一套高度/透明度过渡展开,允许中途反向收起,关闭内容立即进入 inert 状态且保留内部状态。方向键上下、Home/End 移动焦点,左右键展开/收起嵌套;减少动态效果时直接切换。AppShell 共享桌面/移动导航状态,SettingsLayout 使用 SideBar variant="indicator" 并保留原有 value/groups API,窄屏使用分类选择器。旧的 SidebarNavigation、NavigationButton、Indicator 导出继续兼容。

NavBar 独立提供顶部品牌、链接、下拉导航和 actions,使用 items、active 及可选 onNavigate;窄屏切换到抽屉,未提供回调时保留浏览器跳转。示例位于「导航组件 → 侧栏与导航条」。

浮层滚动(0.6.10 候选)

Popover 默认由外框滚动,最大高度为 360px。带独立列表的组合组件使用 scrollable={false},通过弹性布局让列表在可用空间内收缩,搜索和底部操作保持固定。日历与图标、字符选择器使用 maxHeight={Infinity} 按内容展开,仍受视口边距限制;空间不足时日历保留外框滚动,图标和字符只滚动内部列表。

设置项与表单

统一设置行使用 SettingRow,提供 title、description、右侧 children 和 divider;设置页面容器为 SettingsLayout / SettingsCard。表单以 Form + FormField + useFormState 组合,FormGroup 负责相关字段分组,FormErrorSummary 统一展示错误,FormDialog 提供表单弹窗。Form 支持 stacked / inline 布局及 labelWidth,提交时自动维护 busy/disabled 状态。

基础输入包括 Input、Textarea、PasswordField、NumberInput、SearchField、PinInput、TagInput、ShortcutInput;选择包括 Checkbox、RadioGroup、Switch、Select、Combobox、MultiSelect、TreeSelect、Cascader、Segmented。日期、颜色、图标、文件与滑动输入继续使用对应的 DatePicker / DateRangePicker、ColorField / ColorPicker、IconPicker / EmojiPicker / SymbolPicker、FilePicker / Upload、Slider / RangeSlider。

标签创建与导航分组(0.5.1)

MultiSelect display="tags" 将可移除标签放在同一个触发框内;可选 onCreate(label) 返回新选项值(支持 Promise)。搜索结果中显示创建入口,成功后连续多选;错误可重试,关闭或卸载后不再应用异步结果。原有摘要模式和静态选项用法保持兼容。

<MultiSelect
  label="标签"
  display="tags"
  value={tags}
  options={options}
  onChange={setTags}
  onCreate={(name) => name}
/>

AppShell.navigationGroups 支持 {id, label?, items} 分组,主导航、标签或其他入口共享分隔与标题样式,桌面与移动抽屉一致;不传时沿用 navigation。Page.title 可省略或传 ReactNode,可在无标题内容区复用共享入场动画。

操作面板(0.5.0)

ActionSheet 使用带无障碍名称的更多图标按钮打开底部操作面板;items 支持 label、icon、disabled、danger 和 action。选择后先完成关闭和焦点恢复,再执行操作,可安全打开另一个弹窗。桌面为紧凑面板,手机贴合底部安全区域。

<ActionSheet
  label="图片操作 1"
  title="图片操作"
  items={[
    { label: "编辑图片", action: editPhoto },
    { label: "移除图片", danger: true, action: removePhoto },
  ]}
/>

横向 FormField 内包含 Textarea 时,标签自动靠上排列;手机仍使用纵向布局。Drawer.onAfterClose 可在关闭动画与焦点恢复完成后执行后续操作。 带下划线导航的抽屉可传 headerDivider={false},仅去掉抽屉标题区的分割线,保留页签与正文中的分组线。

嵌套侧栏(0.6.0)

AppShell.navigation 支持多层 children。异步节点可传 expandable: true,通过 content 提供加载、空状态或重试操作。链接与展开按钮分离,保留新标签打开行为,展开按钮支持键盘和 aria-expanded / aria-controls。

expandedIds + onExpandedChange 提供受控展开;defaultExpandedIds 提供非受控初值。展开以稳定节点 ID 保存,刷新数据或整体折叠不丢失状态。宿主根据路由主动展开祖先,并自行决定何时请求子节点。桌面和手机抽屉共用状态;桌面整体折叠不会隐藏手机抽屉的节点文字。

可单独使用 SidebarNavigation,支持 items、active、onNavigate、basePath、compact 和相同的展开参数。原有扁平导航和导入路径保持兼容。

使用

npm install @robert-stackflow/oneui
import {
  ThemeProvider,
  UIProvider,
  ToastProvider,
  Button,
} from "@robert-stackflow/oneui";
import "@robert-stackflow/oneui/styles/themes.css";
import "@robert-stackflow/oneui/styles/base.css";

export function App() {
  return (
    <ThemeProvider theme="minimal" mode="system">
      <UIProvider>
        <ToastProvider>
          <Button variant="primary">继续</Button>
        </ToastProvider>
      </UIProvider>
    </ThemeProvider>
  );
}

theme 支持 minimal(极简)、blue(蓝白);mode 支持 light、dark、system。也可以给 ThemeProvider 传入由 appearanceDefaults()、normalizeAppearance() 产生的完整 appearance,与 AppearanceSettings 共同使用。外观配置的保存与恢复由应用负责。

ThemeProvider 管理当前文档的主题,应用根部放置一个即可。颜色模式、动效、字体、密度、圆角和自定义配色均由共享层应用。

蓝白默认色板取自 Moment 的 admin/src/styles.css 最终变量及 admin/src/main.tsx 的 victoria 色阶:浅色背景 #F5F7FB、面板 #FFFFFF、正文 #25324A、次级文字 #8592A8、边框 #E3E8F1。导航/焦点蓝为 #5067B8,主按钮为 #4059AA,开关为 #526EDB;深色同样使用 Moment 的对应值。各颜色用途分开配置,不再共用一种近似蓝。

normalizeAppearance 使用 paletteVersion: 2 兼容旧蓝白默认值;非默认自定义配色保留,已带版本的显式颜色也不会被迁移。Desktop 与 Web 共用该规范化函数。参考值和源码摘要保存在 tests/fixtures/moment-palette.json,验证不依赖 Moment 或 Mantine 安装。

蓝白输入与选择控件的 hover 边框复用 Moment 的混色规则:强调色 35% 与基础边框色混合。聚焦或展开时使用完整强调色,错误状态保持错误色;禁用、只读控件不响应 hover。图标、Emoji 和符号选择器的分类栏使用透明背景与主题选中块,不继承普通块状标签页的底板和投影。

边界

  • AppShell 通过导航数据和 onNavigate 接入任何路由或状态机制。
  • headerActions、sidebarFooter、windowControls 为应用能力插槽;draggable 仅标记 header 的拖动区域。
  • UIProvider 配置 Toast 位置、Tooltip 位置和必填标记;组件不读取宿主设置。
  • 普通组件也支持子路径导入,例如 @robert-stackflow/oneui/Input。
  • 页面直接复用 Form / FormField / useFormState 的校验与提交状态、Alert 的错误反馈和 ConfirmDialog 的确认流程;避免另写原生表单、按钮样式或错误提示。
  • Button 支持 href,渲染标准链接并沿用按钮样式;禁用或加载时阻止导航。Card 传入 onClick 后渲染可通过键盘激活的按钮卡片。导航与业务回调由消费应用提供。
  • CSS Modules 随组件分发,由消费项目的构建工具处理。图标/字符目录通过标准 new URL(..., import.meta.url) 加载随包资源。
  • React 和 React DOM 为 peer dependencies(^19.2.0),不打入组件包。独立消费验证覆盖 React 19.3.1,以及 React 19.3.0 + TypeScript 5.9.3;浏览器验证使用 Chromium。

弹窗与加载状态

Dialog 用于自定义内容,支持 small / medium / large。MessageDialog 提供语义图标、消息与主操作按钮,ConfirmDialog 提供普通、危险操作确认,FormDialog 提供有统一字段间距的表单及保存操作。三者均可从根入口或对应组件子路径导入。

确认与表单支持异步回调,等待期间禁止重复提交及关闭,失败时保留内容并显示错误;回调返回 false 可保留弹窗。FormDialog 接收共享 useFormState 的 controller,字段使用 FormField,onSubmit 接收校验后的 values,错误样式与普通 Form 一致。

LoadingState 复用 Spinner;showLabel={false} 仅显示动画,fullPage 用于页面内容区域。应用自行放置等待边界,保留路由外壳。

以上 API 从 0.2.0 起提供。

概览卡片与内置目录(0.4.2)

Card 可通过 title、description、action 组合概览与操作;省略 children 时不会渲染空白正文。图标选择器不传 options 即使用库内置的完整目录;valuePrefix="lucide:" 可保留宿主保存值的前缀。图标、Emoji 和符号资源均由组件库按需加载,支持 Vite 的开发预打包与生产构建,宿主无需维护另一套选项或资源加载器。

弹窗焦点与分页(0.4.1)

Dialog 和 Drawer 在普通关闭、条件卸载时都会恢复触发控件的焦点,支持 StrictMode 和嵌套弹窗。异步打开导致触发按钮在加载期间失焦时,可传入 returnFocus={triggerRef} 明确返回位置;已卸载、禁用或位于其他模态层之外的目标不会被聚焦。

Pagination 的 total 是总条数,pageSize 是每页条数。compact 移除外层留白并在窄屏重排页码、统计和跳转,size="small" 使用当前主题的小尺寸控件;正常和紧凑模式均支持长页码列表换行。宿主可通过 className 调整外层位置。

<Pagination
  compact
  size="small"
  page={page}
  pageSize={10}
  total={records.total}
  onPageChange={setPage}
/>

层级选择、补全与标签

  • TreeSelect variant="category" 在原有树选择交互上增加图标底块、子项数量与层级连线;默认 variant="tree" 保留简洁样式。两种样式均支持搜索、父子联动、多选、禁用、异步加载及键盘操作。HierarchyOption.count 可单独提供数量。
  • TreeTable 复用 Table 的列定义,接收 rows、rowKey、getChildren、rowLabel;通过 expanded / onExpandedChange 控制展开,或使用 defaultExpanded / defaultExpandAll。treeColumn 默认为第一列,支持多级连线、方向键导航及独立行操作。Column.align、Column.width 可用于对齐和列宽。
  • Combobox mode="input" 直接在触发框输入并在下方显示候选,保留 loadOptions、onCreate 和键盘选择。输入中的文本只用于搜索;选择候选或创建成功才提交选项值,关闭时恢复已选标签。默认 mode="panel" 继续使用弹层内搜索。
  • 需要自由文本补全时加 allowCustomValue:每次输入直接更新值,失焦或回车不会强制替换成候选;方向键后回车或点击仍可选择候选。onChange(value, option?) 在主动选择时提供对应选项,自由输入时不提供选项,可用于区分手写地点与带坐标的地点候选。
  • MultiSelect display="tags" 在触发框内展示可移除标签,复用 TagInput 的标签样式;默认 display="summary" 保留文字摘要。两种模式共享连续选择、搜索、数量限制和表单值。只读标签不可移除,禁用选项保持不可操作。

菜单项间距统一为 --menu-item-spacing: 1px,菜单快捷键为靠右的纯文字提示,不预留空的指示器位置。Desktop 与 Web 共用示例:/pickers?view=hierarchy、/forms?view=advanced、/data?view=hierarchy;层级表格中的增删改仅更新示例内存数据。以上扩展从 0.2.0 起提供。

接入现有应用(0.3.0)

AppShell 默认仍显示 OneUI 品牌和顶部栏。可通过 brandName、brandIcon 设置品牌,或用 brand 替换完整品牌内容;homePath 指定宿主内部首页,basePath="/admin" 为实际链接添加基础路径。onNavigate 收到未加基础路径的内部路径,适合 React Router basename;Ctrl/Cmd 点击和新标签页使用完整 href。showHeader={false} 保留移动端浮动导航按钮。settingsItem 和 onCollapsedChange 可省略。自定义完整品牌内容由宿主负责紧凑侧栏适配。

<AppShell
  brandName="Moment"
  brandIcon={<Brand />}
  homePath="/workbench"
  basePath="/admin"
  showHeader={false}
  navigation={navigation}
  active={active}
  title={title}
  onNavigate={navigate}
>
  {children}
</AppShell>

组件外通知使用独立服务,并将同一实例交给 Provider;不需要在 API 模块调用 Hook。未挂载时保留最新消息;notify 返回该消息的关闭函数,旧消息的关闭函数不会关闭新消息。dismiss 触发关闭动画,clear 立即清除。默认仍只显示最新一条通知,多个控制器相互隔离;服务端渲染时应为每个应用/请求创建实例。

// notifications.ts
export const notifications = createToaster();
export const notifyError = (error: Error) =>
  notifications.notify(error.message, { tone: "error" });
// application root
<ToastProvider controller={notifications}>{children}</ToastProvider>;

IconPicker valuePrefix="lucide:" 将内置图标名转换为带前缀的存储值;options 可提供 { value, label, icon, keywords?, category? } 自定义目录,选择后原样返回 value。自定义目录不加载内置图标资源,设置 options 时不应用 valuePrefix。IconPickerProps、IconPickerOption 可从根入口或组件子路径导入。

DatePicker mode="datetime" timeZone="Asia/Shanghai" seconds clearable 使用指定 IANA 时区的今天/此刻,并支持清空及 placeholder。value 始终是 YYYY-MM-DDTHH:mm[:ss] 日历字段字符串;时区参数不把输入值变成时间戳,也不校验夏令时缺口/重复时间。定时发布、UTC 换算和时区歧义规则由宿主业务负责。无 timeZone 时继续使用设备本地时间。

分类迁移时,如原应用父子分类独立选择,使用 TreeSelect multiple checkStrictly;图片上传的 EXIF/GPS、接口结果转换、串行策略(concurrency=1)与未保存状态属于宿主逻辑。

构建与打包

在仓库根目录运行 npm run pack:ui。源码工作区供两端即时开发使用;发布内容单独生成到本目录 dist,含 ESM、TypeScript 声明、CSS 和资源。构建使用干净的临时目录并检查所有包内引用,成功后替换 dist,避免旧文件混入。dist/package.json 只导出生成内容。

发布内容已通过独立 Vite 消费项目验证。包的许可为 UNLICENSED;资源目录内保留图标许可文件。

设置与账户项目

Form / FormGroup / FormField 的 layout 支持 stacked(默认)与 inline,子字段继承并可覆盖;labelWidth 可设数字像素或 CSS 宽度。inline 在 700px 以下自动改为上下排列。标签、帮助、错误与控件共享同一字段状态。

NumberInput 使用 nullable value={numberOrNull} onChange={setValue} 允许留空,清空并提交时返回 null;默认数字 API 保持不变。

AccountItem 接受标题、图标、描述、元数据及操作。PasskeyItem 和 SessionItem 封装通行密钥及登录会话布局,回调只通知宿主操作;不依赖账户接口或日期格式。

0.6.0 应用组合

新增嵌套 SidebarNavigation、ResourceCard、AuthLayout、PageHeading、TableMarkup、布局与文本基础组件、CopyButton 和 BarChart。Surface 复用 Card 的样式,TableMarkup 复用 Table 的样式,页面标题复用 Page。普通下拉继续使用 Select;带搜索的选择直接使用既有 Combobox,搜索栏使用 SearchField;数据概览使用 Statistic,键值详情使用 Descriptions,不增加另一套选择或统计样式。

扩展 Menu 的自定义触发内容、NumberInput 单位、Pagination 汇总显隐、Badge 原生属性、Tooltip 禁用选项及 Button 文字链接。修复日历月份标签碰撞和宽度适配,表格容器继承外框圆角。既有导出与默认 API 保持兼容。

验证:npm run test:sidebar-navigation、npm run test:visual-foundations、npm run test:account-forms、npm run test:modal-pagination、npm run test:package。新增回归覆盖 React 间距覆盖、正文颜色、表格圆角与文字按钮、现有 Combobox 键盘筛选、日期标签和窄屏溢出。

Menu 支持 iconOnly:<Menu iconOnly label="更多操作" items={items} /> 复用 IconButton,默认显示更多图标;trigger 可替换图标,variant 可设置按钮类型。

TableOfContents 的沉浸式完整目录使用 railLayout="outline":沿用树形层级、当前章节高亮和自动滚动,浮窗锚定整条 rail 并使用共享箭头。popoverSide="right" 向外侧留白展开,空间不足时由 Popover 翻转避让;默认 preview 与左侧展开保持兼容。完整目录限高60dvh,可独立滚动。

Lightbox

Lightbox is a controlled image viewer: pass open, items, index, onIndexChange and onClose. Each item has a stable id, src, alt and optional caption, thumbnailSrc, width and height. The optional sourceElement(item) resolves the original image for Hero motion; onLocate(item) runs after exit and scroll unlocking. Supply labels for localization.

The viewer uses an opaque black canvas with light controls independently of the document color mode. It supports captions, thumbnail navigation, non-wrapping previous/next, arrow keys, Escape, original-size zoom, bounded dragging, touch pinch/swipe and manual retry of the original URL. A single image hides navigation. Only adjacent full images are preloaded. It uses native modal isolation and shared OneUI focus, scroll lock and motion; reduced motion and missing/offscreen source elements use a quiet fallback. Keep the component mounted through exit and retain the selected index. Resolve resource permissions and document anchors in the host, not inside OneUI.

Image changes retain the existing outgoing image for a directional fade/slide, without remounting it for the animation. Thumbnail selection uses a moving outline and a separate keyboard focus ring. Shared modal scroll locking preserves classic scrollbar space, nested lock ownership and original document styles.

Clicking empty viewer space closes it. Pointer origin, movement and cancellation are tracked so image/control clicks, dragging and multi-pointer gestures do not accidentally dismiss it. Escape and the close button remain available.

Closing returns a visible source image with Hero motion. Missing/offscreen sources, zoomed images and origin-resolution errors use a gentle image fade/scale; the opaque black canvas fades with the surface rather than leaving a solid backdrop that snaps away. The canvas spans the viewport while the underlying document retains its scrollbar gutter.

Multiline option descriptions

SelectOption.descriptionLines opts into two or three wrapping description lines in Combobox and Select. Use description: "identifier\nShort explanation", descriptionLines: 3 for rich choices. MenuItem supports the same property. The default remains one truncated line. Search still includes the complete description.

原生约束表单(0.6.41)

已有 React 事件表单可改为 <Form onSubmit={submit}>,保留事件处理、受控值和业务请求。Form 统一处理 required、type、pattern、范围、自定义有效性、首个错误焦点和异步提交锁;错误通过 FormField / Input 的 FieldMessages 展示。未包裹的原生字段使用可聚焦的错误摘要。validationMode="blur" 在离开字段后检查,默认提交时检查;出错后修改会更新反馈。内部自动使用 noValidate,不出现原生气泡。

validateForm(formRef.current, false) 检查并展示字段错误但不抢焦点,适合自动保存;省略第二个参数则聚焦首个错误。保留自定义业务错误、身份验证、并发和请求重试策略。字段使用稳定 id 或 name,并通过 OneUI FormField / 控件提供标签。controller={useFormState(...)} 模式保持兼容,用于显式规则与异步字段校验。