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

uni-flow-design

v1.0.1

Published

A zero-API-dependency flow designer component library for Vue, React and plain web apps.

Readme

uni-flow-design

一个零接口依赖的流程设计器组件库。宿主只需要提供 DOM 容器,即可通过 new UniFlowDesign(container, options) 挂载流程画布;节点设置抽屉、流程属性、保存接口由宿主应用自行实现。

README 会作为 npm 包详情页的主要展示内容。发布到 npm 前建议保持这份文档和 dist/module.d.ts 一致。

特性

  • 基于 Vue 3 和 ant-design-vue,产物以 library mode 输出。
  • 可在 Vue、React 或普通 Web 页面中使用。
  • 支持开始、审批、抄送、处理、条件分支节点。
  • 支持缩放、全屏、节点增删、条件分支增删。
  • 点击节点只抛出 node-click,宿主自行渲染设置抽屉。
  • 支持 flowOptions 控制可新增节点类型、最小节点数量、节点展示文案。
  • 导出完整 TypeScript 类型和工具方法。

安装

pnpm add uni-flow-design

宿主还需要安装 peer dependencies:

pnpm add vue@^3.2.25 ant-design-vue@^4 @ant-design/icons-vue@^7.0.1 dayjs@^1.11.13 lodash@^4.17.21

宿主入口需要引入样式(antdv 4 基础样式 reset.css + 本组件样式):

import 'ant-design-vue/dist/reset.css';
import 'uni-flow-design/dist/style.css';

antdv 4 采用 CSS-in-JS,已移除 antdv 3 的 antd.variable.min.cssuiOptions.primaryColor 会写入挂载根的 --ant-primary-color,画布自身样式直接消费它(与 antdv 版本无关);组件内嵌的 antdv 控件主色若需跟随,宿主可用 <a-config-provider :theme="{ token: { colorPrimary } }"> 统一配置。

快速开始

import { UniFlowDesign } from 'uni-flow-design';
import 'ant-design-vue/dist/reset.css';
import 'uni-flow-design/dist/style.css';

const designer = new UniFlowDesign('#flow-root', {
  uiOptions: {
    primaryColor: '#1677ff'
  }
});

designer.on('node-click', (payload) => {
  // 宿主在这里打开自己的设置抽屉
  // 抽屉保存后调用 designer.updateNode(payload.uid, editedNode)
});

function onSave() {
  if (!designer.validate()) {
    designer.markInvalid();
    return;
  }

  const flow = designer.getValue();
  // 调用宿主自己的保存接口
}

// 页面销毁时调用
designer.unmount();

页面容器需要有明确高度:

<div id="flow-root" style="height: 100vh"></div>

Vue 示例

<template>
  <div style="display:flex;flex-direction:column;height:100vh">
    <div style="padding:12px;text-align:right">
      <button @click="onSave">保存</button>
    </div>
    <div ref="root" style="flex:1;min-height:0"></div>
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
import { UniFlowDesign, NodeType, type NodeClickPayload, type FlowNode } from 'uni-flow-design';
import 'ant-design-vue/dist/reset.css';
import 'uni-flow-design/dist/style.css';

const root = ref<HTMLElement | null>(null);
let designer: UniFlowDesign | undefined;

onMounted(() => {
  if (!root.value) return;

  designer = new UniFlowDesign(root.value, {
    flowOptions: {
      addableNodeTypes: [NodeType.Approval, NodeType.Cc, NodeType.Transactor, NodeType.Condition],
      display: {
        startLabel: '发起人'
      }
    }
  });

  designer.on('node-click', (payload: NodeClickPayload) => {
    openNodeDrawer(payload, (editedNode: FlowNode) => {
      designer?.updateNode(payload.uid, editedNode);
    });
  });
});

function onSave() {
  if (!designer?.validate()) {
    designer?.markInvalid();
    return;
  }
  const flow = designer.getValue();
}

onBeforeUnmount(() => designer?.unmount());
</script>

React 示例

import { useEffect, useRef } from 'react';
import { UniFlowDesign } from 'uni-flow-design';
import 'ant-design-vue/dist/reset.css';
import 'uni-flow-design/dist/style.css';

export default function FlowPage() {
  const rootRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (!rootRef.current) return;

    const designer = new UniFlowDesign(rootRef.current, {});
    designer.on('node-click', (payload) => {
      // 打开宿主自己的节点设置面板
    });

    return () => designer.unmount();
  }, []);

  return <div ref={rootRef} style={{ height: '100vh' }} />;
}

参数

export interface UniFlowDesignProps {
  defaultValue?: FlowNode | string;
  isPreviewStatus?: boolean;
  flowOptions?: FlowOptions;
  uiOptions?: FlowUiOptions;
}

export interface FlowUiOptions {
  primaryColor?: string;
  theme?: 'light' | 'dark';
}

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | defaultValue | FlowNode \| string | 默认开始节点 | 初始流程 JSON,可传对象或 JSON 字符串 | | isPreviewStatus | boolean | false | 预览态;为 true 时隐藏编辑入口并禁用节点点击 | | flowOptions | FlowOptions | 见下方 | 画布能力与展示配置 | | uiOptions | FlowUiOptions | 见下方 | UI 配置,例如主题色、明暗主题 |

uiOptions

| 参数 | 默认值 | 说明 | | --- | --- | --- | | primaryColor | #40a9ff | 主题主色,写入挂载根 --ant-primary-color 驱动画布主色(antdv 4 控件主色建议宿主用 ConfigProvider theme 配置) | | theme | 'light' | 画布明暗主题初始值,运行时可用 setTheme 切换 |

flowOptions

节点类型统一用 NodeType 枚举表示:

export enum NodeType {
  Launch = 'LAUNCH',                // 发起 / 开始
  Approval = 'APPROVAL',            // 审批
  Cc = 'CC',                        // 抄送
  Transactor = 'TRANSACTOR',        // 处理
  Condition = 'CONDITION',          // 条件分支
  ConditionTerm = 'CONDITION_TERM'  // 条件项(条件分支内的一条条件)
}

export interface FlowOptions {
  addableNodeTypes?: AddableNodeKind[];
  minNodeCounts?: Partial<Record<AddableNodeKind, number>>;
  display?: FlowDisplayOptions;
}

// 可新增的节点类型(不含发起节点)
export type AddableNodeKind =
  | NodeType.Approval
  | NodeType.Cc
  | NodeType.Transactor
  | NodeType.Condition;

export interface FlowDisplayOptions {
  startLabel?: string;
}

| 参数 | 说明 | | --- | --- | | addableNodeTypes | 允许新增的节点类型。可选 NodeType.Approval 审批、NodeType.Cc 抄送、NodeType.Transactor 处理、NodeType.Condition 条件分支。默认全部允许 | | minNodeCounts | 节点最小保留数量,例如 { [NodeType.Approval]: 1 } 表示至少保留 1 个审批节点 | | display.startLabel | 开始节点显示文案,默认 发起人 |

节点标题的取值规则:

  • 开始节点(NodeType.Launch)始终显示 display.startLabel
  • 其余节点统一显示节点自身的 name。新建节点的默认 name 为内置文案(审批 / 抄送 / 处理 / 条件判断),改名通过 setNodeName(uid, name) 写入 node.name 即可反映到画布。

示例:只允许新增审批节点,并至少保留一个审批节点:

new UniFlowDesign('#flow-root', {
  flowOptions: {
    addableNodeTypes: [NodeType.Approval],
    minNodeCounts: { [NodeType.Approval]: 1 },
    display: {
      startLabel: '发起'
    }
  }
});

事件

designer.on('node-click', (payload) => {});
export interface NodeClickPayload {
  node: FlowNode;
  nodeConfigAll: FlowNode;
  type: FlowNodeKind;
  uid: FlowId;
  conditionTermIndex?: number;
}

| 字段 | 说明 | | --- | --- | | node | 被点击节点的副本 | | nodeConfigAll | 当前整棵流程树 | | type | 节点类型(NodeType):Launch 开始,Approval 审批,Cc 抄送,Transactor 处理,Condition 条件分支 | | uid | 节点唯一标识,写回节点时使用 | | conditionTermIndex | 仅条件分支有效,表示点击的是第几个条件项 |

在抽屉里设置节点名称

监听 node-click 打开业务抽屉,确定时调用 setNodeName(uid, name) 写回,画布标题即显示该 name(开始节点除外,始终显示 startLabel):

const designer = new UniFlowDesign('#flow-root');

designer.on('node-click', (payload) => {
  // 打开宿主自己的抽屉,初始值取 payload.node.name
  openDrawer(payload.node.name, (newName: string) => {
    designer.setNodeName(payload.uid, newName); // 确定保存,画布即时更新
  });
});

实例方法

| 方法 | 返回值 | 说明 | | --- | --- | --- | | on('node-click', fn) | void | 监听节点点击 | | getValue() | FlowNode | 获取当前画布流程树 | | setValue(value) | unknown | 整树覆盖当前画布 | | updateNode(uid, node) | unknown | 按 uid 写回宿主抽屉编辑后的节点 | | setNodeName(uid, name) | boolean | 按 uid 更新节点名称,命中返回 true。画布标题即显示该 name(开始节点除外) | | setTheme(mode) | unknown | 运行时切换明暗主题,mode'light''dark',画布即时变色 | | validate() | boolean | 校验流程是否配置完整,true 表示通过 | | markInvalid(show?) | unknown | 高亮未配置完整的节点 | | unmount() | void | 卸载组件实例 |

明暗主题

构造时用 theme 设初始值,页面里的明暗开关调用 setTheme(mode) 即时切换,无需重建实例:

const designer = new UniFlowDesign('#flow-root', { theme: 'light' });

// 页面开关
themeSwitch.onChange((checked) => {
  designer.setTheme(checked ? 'dark' : 'light');
});

画布所有可变颜色都走 --uf-* CSS 变量(定义在挂载根元素上),需要微调配色时,可在宿主样式里覆盖:

/* 覆盖暗色画布背景与节点卡片色 */
.uni-flow-design[data-theme="dark"] {
  --uf-canvas-bg: #18181b;
  --uf-node-bg: #27272a;
}

常用变量:--uf-canvas-bg(画布背景)、--uf-node-bg(节点卡片)、--uf-text / --uf-text-secondary(文字)、--uf-line(连线)、--uf-border(分隔线)、--uf-approve-bg / --uf-handle-bg / --uf-send-bg(审批/处理/抄送节点底色)。

antd 的抽屉、下拉、tooltip 等组件由宿主提供,其暗色样式需宿主自行配置(如 antd 的 theme.darkAlgorithm);本组件的 theme 只负责画布自身。

工具方法

import {
  NodeType,
  createDefaultFlow,
  flowCheckIsSetting,
  flowTransformData,
  flowTransToXML
} from 'uni-flow-design';

| 导出 | 说明 | | --- | --- | | NodeType | 节点类型枚举(字符串值),用于 addableNodeTypespayload.type 比较等 | | createDefaultFlow() | 生成默认开始节点流程 | | flowCheckIsSetting(flow) | 检查流程是否存在未配置项 | | flowTransformData(flow) | 保存前转换流程数据,补齐流转关系 | | flowTransToXML(flow) | 将流程 JSON 转为 Flowable XML |

数据类型

包内导出常用类型:

import type {
  FlowId,
  FlowNode,
  FlowNodeKind,
  FlowOptions,
  FlowUiOptions,
  FlowUser,
  AddableNodeKind,
  FlowDisplayOptions
} from 'uni-flow-design';

UMD 使用

UMD 产物不会打包 peer dependencies。使用前需要先准备这些全局变量:

  • Vue
  • antd
  • IconsVue
  • dayjs
  • _
<link rel="stylesheet" href="https://unpkg.com/ant-design-vue@4/dist/reset.css" />
<link rel="stylesheet" href="./dist/style.css" />
<div id="flow-root" style="height: 100vh"></div>

<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/dayjs@1/dayjs.min.js"></script>
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
<script src="https://unpkg.com/ant-design-vue@4/dist/antd.min.js"></script>
<script src="https://unpkg.com/@ant-design/icons-vue@7/dist/index.umd.min.js"></script>
<script src="./dist/index.umd.js"></script>
<script>
  const designer = new window.UniFlowDesign.UniFlowDesign('#flow-root', {});
</script>

本地开发

pnpm install
pnpm dev

构建:

pnpm build

类型检查:

npx tsc --noEmit

发布到 npm

npm 包详情页会展示 README.md,所以需要有 npm 展示文档。发布前建议执行:

pnpm build
npx tsc --noEmit
npm pack --dry-run

确认包内容至少包含:

  • package.json
  • README.md
  • dist/index.es.js
  • dist/index.umd.js
  • dist/style.css
  • dist/module.d.ts
  • dist/services.d.ts
  • dist/flowDesign/type.d.ts

首次发布:

npm login
npm publish --access public

后续发布前需要更新版本号:

npm version patch
npm publish

设计边界

组件只负责流程画布本身:

  • 组件负责:画布渲染、节点增删、条件分支增删、缩放、全屏、节点点击事件。
  • 宿主负责:节点设置抽屉、保存按钮、流程属性、接口请求、业务校验。

这个边界能保证组件不绑定具体业务模块,也不会因为新增业务场景再改组件内部。