@composy/tool-ui

Vue 3 tool UI foundation for LDesign workspaces, with a reusable shell and typed Node bridge support.
Install
npm install @composy/tool-ui
Latest Version:0.0.2
Vue:3
License:MIT
Last Updated:Oct 12, 2026
Links: npm
Maintainer: swimly

@composy/tool-ui

@composy/tool-ui 是 LDesign 内部工具体系的 Vue 3 基础 UI 包。它把工具壳层、路由导航、主题系统、前后端桥接协议,以及常用业务组件收敛成一套可复用的统一能力,适合构建运维台、数据控制台、工作台、日志面板和命令执行界面。

核心能力

  • 统一壳层:createUI、ToolShell、分组导航、面包屑、主题切换、状态栏。
  • 类型安全桥接:defineUIBridge、defineUIBridgeMethod、createUIBridgeClient、服务端挂载辅助。
  • 模块化装配:defineUIToolModule、composeUIToolModules、createToolHost。
  • 组件库:表单、展示、日志、图表、覆盖层、终端、日期选择、树形视图、上传等。
  • 样式运行时注入:无需业务工程重复维护基础样式入口。

适用场景

  • 需要快速搭建内部工具壳层,并统一导航与视觉风格。
  • 需要把前端页面与 Node/服务端能力通过统一协议对接。
  • 需要复用一批偏控制台风格的 Vue 3 组件,而不是从零组织样式与交互。

安装

pnpm add @composy/tool-ui vue vue-router

如果在 LDesign monorepo 内使用,通常直接通过 workspace 依赖接入即可。

包结构

src/
  bridge/       桥接定义、客户端与共享路径解析
  components/   Tool* 组件集合
  composables/  useUITool / useUiBridge
  core/         createUI、路由与上下文
  dom/          焦点、滚动锁、浮层定位、环境判断
  server/       桥接挂载与命令桥接服务端实现
  styles/       主题变量与基础样式注入
  types/        统一类型出口

包级 ESLint、TypeScript 与 @composy/pack 主配置位于 .ldesign/;根目录的 ESLint 与 TypeScript 文件是兼容入口。

快速开始

import { Home } from 'lucide-vue-next'
import { defineComponent, h, ref } from 'vue'
import {
  ToolButton,
  ToolDescriptions,
  ToolGrid,
  ToolPage,
  ToolPanel,
  ToolTerminal,
  ToolTimeline,
  createUI,
  toolCommandBridge,
} from '@composy/tool-ui'

const OverviewPage = defineComponent({
  name: 'OverviewPage',
  setup() {
    const command = ref('pnpm -s test -- --run')

    return () =>
      h(
        ToolPage,
        {
          eyebrow: 'Workspace',
          title: '发布控制台',
          description: '把元信息、时间线和命令执行放进同一套工具壳层中。',
        },
        {
          actions: () => [
            h(ToolButton, { variant: 'secondary' }, () => '刷新'),
            h(ToolButton, () => '发布'),
          ],
          default: () => [
            h(ToolGrid, { columns: 2, min: 320 }, () => [
              h(
                ToolPanel,
                { title: '构建信息' },
                {
                  default: () =>
                    h(ToolDescriptions, {
                      columns: 2,
                      items: [
                        { label: 'Region', value: 'ap-southeast-1', copyable: true },
                        { label: 'Commit', value: 'c1a4d02', copyable: true },
                        { label: 'Artifact', value: 'release-surface.tgz', span: 2 },
                      ],
                    }),
                }
              ),
              h(
                ToolPanel,
                { title: '流水线时间线' },
                {
                  default: () =>
                    h(ToolTimeline, {
                      items: [
                        { title: '构建排队', time: '09:41', tone: 'accent' },
                        { title: '产物上传', time: '09:44', tone: 'success' },
                        { title: '预热待执行', time: '09:46', tone: 'warning' },
                      ],
                    }),
                }
              ),
              h(
                ToolPanel,
                { title: '命令终端', padding: 'none' },
                {
                  default: () =>
                    h(ToolTerminal, {
                      modelValue: command.value,
                      bridgeId: 'tool-command',
                      cwd: '/workspace/app',
                      'onUpdate:modelValue': (value: string) => {
                        command.value = value
                      },
                    }),
                }
              ),
            ]),
          ],
        }
      )
  },
})

createUI({
  shell: {
    title: 'Workspace Studio',
    subtitle: '内部工具统一工作台',
    accentColor: '#c56f34',
    railBadge: 'Console',
    navigationLabel: '工作台',
    navigationPlaceholder: '搜索页面或模块',
    statusItems: [
      { label: 'ENV', value: 'DEV', tone: 'accent' },
      { label: 'Region', value: 'CN' },
    ],
  },
  routes: [
    {
      path: '/',
      component: OverviewPage,
      meta: {
        title: '概览',
        description: '壳层概览与发布控制',
        group: '核心',
        iconComponent: Home,
      },
    },
  ],
  backend: {
    defaultBridgeId: 'tool-command',
    bridges: [toolCommandBridge],
  },
})

桥接系统

1. 定义桥接协议

import { defineUIBridge, defineUIBridgeMethod } from '@composy/tool-ui'

export const metricsBridge = defineUIBridge({
  id: 'metrics',
  methods: {
    summary: defineUIBridgeMethod<void, { online: number; errors: number }>({
      method: 'GET',
      path: 'summary',
    }),
  },
})

2. 前端调用

import { createUIBridgeClient } from '@composy/tool-ui'

const client = createUIBridgeClient(metricsBridge, {
  baseURL: '/api/ui',
  timeoutMs: 10_000,
})

const summary = await client.summary()

timeoutMs 会在请求超时后主动 abort,并以 UIBridgeError.code === 'REQUEST_TIMEOUT' 返回;也可以传入 signal 取消一组请求,取消错误的 code 为 REQUEST_ABORTED。两者都会通过 RequestInit.signal 传给自定义 fetcher,并在请求结束后清理计时器和事件监听器。

3. 服务端挂载

import { HttpServer } from '@composy/kit/network'
import { mountUIBridgeToKitServer } from '@composy/tool-ui/server'

const server = new HttpServer({ port: 3001, cors: true })

mountUIBridgeToKitServer(server, metricsBridge, {
  async summary() {
    return { online: 128, errors: 2 }
  },
})

命令桥接

内置的 toolCommandBridge 用于支持 ToolTerminal:

  • start:启动命令会话
  • poll:轮询新的 stdout / stderr
  • stop:终止当前会话

服务端示例:

import { HttpServer } from '@composy/kit/network'
import { mountToolCommandBridgeToKitServer } from '@composy/tool-ui/server'

const server = new HttpServer({
  port: 3001,
  cors: true,
})

mountToolCommandBridgeToKitServer(server, {
  basePath: '/api/ui',
  retentionMs: 10 * 60_000,
})

server.start()

模块化装配

如果你的工具由多个独立模块组成,推荐使用模块 API,而不是手动拼 routes 和 bridges:

import { composeUIToolModules, createToolHost, defineUIToolModule } from '@composy/tool-ui'

这套 API 会负责:

  • 为模块根路由拼接 basePath
  • 合并模块级导航元信息
  • 去重桥接定义
  • 在没有根路由时自动补充首页跳转

主题与样式

默认情况下,createUI 会自动完成两件事:

  • 注入基础样式:ensureToolUIStyles()
  • 应用主题变量:setToolUITheme() / setToolUIColorMode()

如果你只复用组件,不通过 createUI 启动壳层,需要手动注入样式:

import { ensureToolUIStyles } from '@composy/tool-ui'

ensureToolUIStyles()

公共入口

  • 根入口:@composy/tool-ui
  • 桥接入口:@composy/tool-ui/bridge
  • 服务端入口:@composy/tool-ui/server

说明:

  • 构建会产出 dist/ 下的完整模块树,便于内部调试与源码映射。
  • 对外稳定公开入口仍以 package.json#exports 为准。

Workbench 宿主入口

面向 Workbench 或其他工具容器时,优先使用轻量入口 @composy/tool-ui/host:

import { createToolHost, defineUIToolModule, ToolShell, useUIBridge } from '@composy/tool-ui/host'

该入口包含统一 Shell、模块组合、宿主创建和桥接 composable,不会把全部业务组件索引带入应用首屏。完整组件库仍通过 @composy/tool-ui 提供。

开发命令

pnpm run type-check
pnpm run lint:check
pnpm run format:check
pnpm run build
pnpm run preview:dev
pnpm run preview:check

构建说明

当前包通过 @composy/pack 的共享 tsup 工作流构建,build 与 dev 脚本显式指定 .ldesign/pack.config.ts:

  • 构建配置:.ldesign/pack.config.ts
  • 入口策略:src/**/*.ts
  • 产物格式:ESM + CJS + .d.ts
  • 输出目录:dist/

这意味着源码目录中的 TypeScript 文件会被完整编译为对应的 dist 模块树,同时保留顶层公开入口。

设计原则

  • 壳层与业务解耦:业务页面只关心路由与页面内容。
  • 桥接协议先行:前后端通过统一类型契约通信。
  • 默认值克制:提供完整基础体验,但尽量保留扩展空间。
  • 运行时低侵入:样式与主题按需注入,不强依赖额外入口文件。

相关文档

  • QUICKSTART.md
  • COMPONENTS.md
  • README.en.md
  • .workspace-ui-runtime

通过 @composy/cli 统一接入

  • 接入类型:helper
  • 统一命令:ldesign tool-ui
  • 命令别名:ui-lib
  • 包内原生 bin:无独立 bin

当前包通过 helper 方式接入,统一命令会调用 @composy/cli 内置封装。

pnpm add -D @composy/cli
ldesign tool-ui --help
ldesign tools run tool-ui --help

Related Packages

@ldesign/desktop

基于vue2和@vue/composition-api桌面端组件库

1,858
@flexdash/node-red-flexdash

Node-RED nodes for the FlexDash dashboard

247,442 10
@midwayjs/vue

Midway Vue API bridge component

2,100 7,760

Version History

Version Released Vue License
0.0.2 3.5.32 MIT
0.0.1 3.5.39 MIT