@iyulab/desktop-patterns

中文文档
0.13.0发布于 2026/11/01MITTypeScriptES Module构建来源已验证

应用程序外壳和结构布局模式组装在上面 desktop-compact原语。框架无关的自定义元素(点燃),零内置字符串,每个内容区域都有一个槽。

中文使用文档
文档目录10 节
  1. 安装
  2. 使用
  3. 被选中的项目旁边的列表
  4. 侧边栏项:链接、组、图标、动作
  5. 主题
  6. 平台边界-阻力区域
  7. 组件
  8. 可访问性
  9. 开发
  10. 许可证

desktop-patterns

应用程序外壳和结构布局模式组装在上面 desktop-compact原语。体系的中立者自定义 元素(点燃),零内置字符串,每个内容区域都有一个槽。

仅结构-原子控件(按钮,输入,对话框)属于 desktop-compact;本地的 平台集成(文件对话框、托盘、窗口控制)属于桌面运行时本身 适配器层,无论应用使用哪个运行时。这个包本身不调用任何平台API, 并且对任何特定的消费应用程序一无所知。

安装

要求节点≥22。

npm install @iyulab/desktop-patterns @iyulab/desktop-compact

只导入你使用的组件——每个船都是它自己的树摇子路径:

import '@iyulab/desktop-patterns/shell'
import '@iyulab/desktop-patterns/sidebar'

或者进口一切通过桶:

import '@iyulab/desktop-patterns'

使用

<dp-shell>
  <dp-sidebar slot="sidebar" active-id="overview" header="My App" id="nav"></dp-sidebar>
  <dp-toolbar slot="toolbar" heading="My App" show-toggle></dp-toolbar>
  <dp-page>
    <h2>Overview</h2>
    <p>Main content.</p>
  </dp-page>
</dp-shell>

items/bottomItems 是数组,所以它们被设置为JS属性(不是普通的HTML属性)-相同 作为任何Lit自定义元素:

document.querySelector<HTMLElementTagNameMap['dp-sidebar']>('#nav')!.items = [
  { id: 'overview', icon: '■', label: 'Overview' },
]

import { desktopMinWidth } from '@iyulab/desktop-patterns/breakpoints' // no elements registered

const shell = document.querySelector('dp-shell')!
const sidebar = document.querySelector('dp-sidebar')!
const toolbar = document.querySelector('dp-toolbar')!
const wide = matchMedia(`(min-width: ${desktopMinWidth}px)`)
let collapsed = false // the consumer's own state: a wide window's sidebar folded to its rail

function sync() {
  sidebar.collapsed = collapsed && wide.matches // a drawer always shows the whole sidebar
  toolbar.expanded = wide.matches ? !collapsed : shell.sidebarOpen
}
wide.addEventListener('change', sync)
sidebar.addEventListener('dp-sidebar-select', () => {
  // consumer owns activeId / routing
})
sidebar.addEventListener('dp-sidebar-activate', () => {
  shell.sidebarOpen = false // a drawer gives way to what was picked — the place already shown included
  sync()
})
toolbar.addEventListener('dp-toolbar-toggle', () => {
  if (wide.matches) collapsed = !collapsed
  else shell.sidebarOpen = !shell.sidebarOpen
  sync()
})
shell.addEventListener('dp-shell-sidebar-close', () => { shell.sidebarOpen = false; sync() }) // backdrop, Escape

在桌面断点(desktopMinWidth, 1024px - desktopMedia (对于组件的样式) 侧边栏是内容上方的一个抽屉,打开时打开 sidebar-open 设置;在它上面 侧边栏位于内容和旁边 sidebar-open 改变不了什么。使用相同的工具栏开关 两种宽度:在窄窗中打开抽屉,在宽窗中折叠侧边栏 铁轨倒塌(dp-sidebar collapsed). 打开开关 expanded 所以辅助技术听到了 它处于哪个状态。消费者拥有两种状态——启动时抽屉关闭,关闭时抽屉关闭 shell问(背景点击,逃离),当一个地方被选中,或一个狭窄的窗口保持覆盖。

外壳控制着窗口的高度,所以文档永远不会滚动——主内容框会滚动。 任何保存和恢复用户正在阅读的位置的操作都会到达该框 shell.mainElement;与 @iyulab/router,把它交给路由器的滚动恢复: scrollRestoration: { container: () => document.querySelector('dp-shell')?.mainElement }.

被选中的项目旁边的列表

<dp-page fill max-width="full">
  <dp-list-detail>
    <nav slot="list" aria-label="People">…</nav>
    <article>…the person picked…</article>
  </dp-list-detail>
</dp-page>

dp-list-detail 把 list 槽位旁边默认槽位,各自滚动,列表 --dp-list-detail-list-width 宽度(默认情况下侧边栏的宽度——导航、列表和项目读取为 1:1:休息)。在桌面断点下面有一个窗格的空间:项目while detail-open 是 设置,否则列表。消费者拥有 detail-open -当一个项目被选中时设置它,并给予 该项目返回清除它的方式,如下所示 desktopMinWidth.

nav.items = [
  { id: 'overview', icon: '■', label: 'Overview', href: '/overview' }, // href → rendered as <a>
  {
    id: 'work', label: 'Work', collapsed: false,                        // a group: a disclosure over its items
    items: [{ id: 'runs', icon: '▶', label: 'Runs', href: '/runs' }],
  },
]
nav.pinnedItems = [{ id: 'settings', icon: '⚙', label: 'Settings' }]   // places kept at the foot of the rail
nav.bottomItems = [
  { id: 'dense', icon: '▤', label: 'Dense mode', pressed: false },    // a toggle: aria-pressed, owned by you
  { id: 'sign-out', icon: '⎋', label: 'Sign out' },                    // actions, not places
]
nav.setAttribute('nav-label', 'Main')                                 // names the navigation landmark
  • href 将项目呈现为链接,这样路由器的链接拦截器(或浏览器)就会进行导航。 dp-sidebar-select 仍然可以发射并且可以取消 preventDefault() 取消导航并保留 活动项目。修改后的单击(Ctrl/⌘/Shift/Alt,中间按钮)会在其他地方打开链接,但不选择任何内容。 项目没有 href 停留按钮和用户导航 dp-sidebar-select.
  • 组 ({ id, label, items, icon?, collapsed? })渲染为一个命名的 role="group" 根据披露 按钮(aria-expanded). 持有活动项的组始终处于打开状态。在倒塌的铁轨上,每一组 项目显示,由规则分隔。
  • 图标:每个物品的图标是一个插槽,命名为 icon-<id> 项目的退路是谁的 icon 文本槽任何图标 元素(<svg slot="icon-overview">)来替换它。
  • dp-sidebar-activate 每次选择导航项时触发,活动项包括(在 dp-sidebar-select 当地点改变时;当这个节目被取消的时候就没有了)。关上抽屉就好了:挑着 已经显示的地方仍然意味着“带我去那里”,而且 dp-sidebar-select 不为它而火。
  • 固定的地方 (pinnedItems)坐在轨道脚下,内部和外部相同的导航地标 滚动列表。它们是这样的地方 items - - - - - - dp-sidebar-select, aria-current, href 都适用-所以a 显示的设置或帮助页面被标记为当前页面。
  • 底部的项是操作:每次点击触发 dp-sidebar-action (itemId) -每次,所以失败的操作可以 他被重新试了一次,然后再也不动了 aria-current. (在0.2。他们开枪了 dp-sidebar-select 然后做了主动标记。)
  • 切换操作底部的动作 pressed ({ id, icon, label, pressed: true | false })是一种设置 打开和关闭。按钮携带 aria-pressed,打开按钮会得到一个安静的背景和一个重音图标 (--dp-sidebar-pressed-bg, --dp-sidebar-pressed-icon-color),这在倒塌的铁轨上仍能看到。以…命名 设置(“密集模式”),而不是点击(“打开密集模式”)。侧边栏不会翻转它-更改值 在 dp-sidebar-action 并设置 bottomItems 再一次。

每个组件都将其面向用户的文本作为纯属性/属性或插槽——没有 内置i18n层。查看每个组件的Storybook故事(npm run storybook)下载完整的API。

主题

在应用的全局样式表中导入这两个令牌表:

import '@iyulab/desktop-compact/tokens.css'
import '@iyulab/desktop-patterns/tokens.css'

颜色/间距/半径/排版都来自 desktop-compact的 --dc-* 令牌-这个包添加 只有结构尺寸 desktop-compact 对…没有概念--dp-sidebar-width, --dp-sidebar-width-collapsed, --dp-header-height, --dp-list-detail-list-width). 每个组件都带有相同的回退 值,因此即使没有样式表也能正确呈现。

平台边界-阻力区域

dp-toolbar 暴露中立 drag-region 旗帜(不是本地的) draggable,这已经意味着 (其他的),但从不发出任何特定于平台的CSS。旗帜向主人反映 属性,但实际拖动面是专用的 part="drag-handle" 起动之间的垫片 组和 actions 槽-从来没有整个主机-所以映射永远不能达到切换 按钮或插槽操作。将该部分映射到实际的窗口拖动行为是控件的工作 平台适配器层,以及如何取决于运行时。webview在哪里尊重CSS app-region 属性(基于chromium的运行时,如Electron),映射是一个规则:

dp-toolbar[drag-region]::part(drag-handle) {
  -webkit-app-region: drag;
}

而从指针事件或标记属性开始窗口拖动的运行时则会执行此操作 同样的部分,不在主机上。

dp-shell 不标记任何自己的拖动区域-它对插入的内容没有意见 toolbar,因此拖拽句柄的所有权完全保留在那里呈现的任何东西(通常是 dp-toolbar)。

组件

组件描述
dp-page具有居中、最大宽度列的可滚动内容区域——每个视图呈现到的页面主体。与 fill 它不滚动,并且它的列与区域一样高,对于滚动其自己的部分的视图(打开的项旁边的列表)
dp-list-detail一个列表旁边的项目从中选择(主-细节)-每个窗格滚动自己;在1024px以下,每次一个窗格 detail-open 设置
dp-sidebarApp-shell导航栏-展开/折叠状态,可选的固定底部组,a footer 任何消费者想要的频道
dp-toolbar应用程序外壳标题栏 heading/subtitle一个可选的侧边栏开关(窄窗口中的抽屉,宽窗口中的折叠),一个右侧 actions 槽
dp-shell顶层布局构成 sidebar/toolbar/banner/main-content区域,在1024px的断点下面有一个响应式抽屉(背景+覆盖侧边栏)
dp-shortcut-overlay只显示键盘快捷键帮助面板- a shortcuts 列表+ open 国旗;没有注册/绑定基础设施(仍然是消费者的)

运行 npm run storybook 以交互方式浏览每个组件,包括 dp-shell 构成真正的 dp-sidebar+dp-toolbar+dp-page 在一起。

可访问性

每个组件都附带一个可访问性测试,作为其测试套件的一部分(npm test). 地标性建筑 遵循ARIA APG惯例- dp-sidebar 使用语义 <nav> (没有冗余的主机级角色), dp-shortcut-overlay 使用 role="dialog" 与 aria-labelledby 指向其可见的标题。

开发

npm install
npm test              # @web/test-runner, real Chromium
npm run typecheck
npm run guard          # platform-neutrality scan (src/ must not call or name a platform API)
npm run build          # per-component ESM output, type declarations
npm run storybook      # interactive component browser

tsc 是TypeScript 7 (@typescript/native),而 typescript 解析为 @typescript/typescript6: TypeScript 7还没有JavaScript编译器API,而声明build会读取一个。别名是 一次 vite-plugin-dts 仅在TypeScript 7上运行。

@iyulab/desktop-compact 是一个 同行 依赖:这个包读取它的 --dc-* 令牌,但从不 导入它的代码,这样使用者安装一个副本,两个包共享它。常规依赖 会给消费者一个更新的吗 desktop-compact 次要的第二个,未使用的副本嵌套在此 包中。

许可证

麻省理工学院

版本与发布记录

@iyulab/desktop-patterns 共发布 29 个版本,首次发布于 2026/09/03;过去 12 个月发布了 29 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.13.0latest2026/11/011 天前
0.12.22026/10/2410 天前
0.12.12026/10/2310 天前
0.12.02026/10/2311 天前
0.11.22026/10/1420 天前
0.11.12026/10/1321 天前

关于 @iyulab/desktop-patterns 的常见问题

@iyulab/desktop-patterns 是什么?

应用程序外壳和结构布局模式组装在上面 desktop-compact原语。框架无关的自定义元素(点燃),零内置字符串,每个内容区域都有一个槽。

如何安装 @iyulab/desktop-patterns?

在项目目录运行 npm install @iyulab/desktop-patterns,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@iyulab/desktop-compact(^0.15.1 || ^0.16.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@iyulab/desktop-patterns 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@iyulab/desktop-patterns 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@iyulab/desktop-patterns 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@iyulab/desktop-patterns 可以商用吗?

@iyulab/desktop-patterns 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@iyulab/desktop-patterns 还在维护吗?

最新版本 0.13.0 发布于 2026/11/01(1 天前);至今共发布 29 个版本,其中过去 12 个月发布了 29 个;首次发布于 2026/09/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。