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

@knotx/decorators

v0.5.8

Published

Decorators for Knotx

Readme

@knotx/decorators

一个为 Knotx 图形编辑器提供装饰器支持的 TypeScript 包,用于简化插件开发过程。

安装

npm install @knotx/decorators

或者使用 yarn:

yarn add @knotx/decorators

或者使用 pnpm:

pnpm add @knotx/decorators

基本概述

@knotx/decorators 提供了一套完整的 TypeScript 装饰器,帮助开发者更高效地创建 Knotx 插件。这些装饰器封装了常见的插件开发模式,包括节点渲染、边渲染、数据管理、生命周期管理等功能。

主要功能

  • 节点管理:提供节点类型定义、操作和管道处理
  • 边管理:提供边类型定义、操作和管道处理
  • 插件管理:提供配置管理、生命周期控制和工具函数注册
  • 数据管理:提供响应式数据绑定和依赖注入
  • UI 管理:提供层级管理和面板渲染

API 文档

节点相关装饰器

@nodeType

用于声明一个方法作为节点渲染器。

import { nodeType } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @nodeType('my-node')
  renderNode(node: Node) {
    return (
      <div className="my-node">
        <h3>{node.data.title}</h3>
        <p>{node.data.content}</p>
      </div>
    )
  }
}

参数

  • type: string - 节点类型标识符

返回值:返回一个 React 组件或 JSX 元素

@nodeOperator

用于声明一个方法作为节点操作函数。

import { nodeOperator } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @nodeOperator()
  addNode(x: number, y: number) {
    return [{
      type: 'add',
      node: {
        id: generateId(),
        type: 'default',
        position: { x, y },
        data: { title: 'New Node' }
      }
    }]
  }

  @nodeOperator()
  deleteNode(nodeId: string) {
    return [{
      type: 'remove',
      nodeId
    }]
  }
}

使用说明

  • 方法必须返回一个操作数组
  • 操作会自动分发到引擎进行处理
  • 支持批量操作

@nodePipe

用于声明一个方法作为节点操作管道,在节点操作执行前后进行处理。

import { nodePipe } from '@knotx/decorators'
import { filter, map } from 'rxjs/operators'

class MyPlugin extends BasePlugin {
  @nodePipe()
  validateNodeOperation() {
    return {
      preOperation: () => filter((operation) => {
        if (operation.type === 'add') {
          return this.validateNode(operation.node)
        }
        return true
      }),
      postOperation: () => map((operation) => {
        console.log('Operation completed:', operation)
        return operation
      })
    }
  }
}

返回值:返回一个包含 preOperationpostOperation 的对象

边相关装饰器

@edgeType

用于声明一个方法作为边渲染器。

import { edgeType } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @edgeType('my-edge', {
    sourcePosition: 'right',
    targetPosition: 'left',
    sourceXOffset: 10,
    targetXOffset: -10
  })
  renderEdge(edge: Edge) {
    return (
      <g>
        <path
          d={edge.path}
          stroke="#333"
          strokeWidth={2}
          fill="none"
        />
        <text x={edge.labelX} y={edge.labelY}>
          {edge.label}
        </text>
      </g>
    )
  }
}

参数

  • type: string - 边类型标识符
  • edgeConfig?: EdgeConfig - 边配置选项
    • sourcePosition: Position - 源连接点位置
    • targetPosition: Position - 目标连接点位置
    • sourceXOffset: number - 源连接点 X 偏移
    • sourceYOffset: number - 源连接点 Y 偏移
    • targetXOffset: number - 目标连接点 X 偏移
    • targetYOffset: number - 目标连接点 Y 偏移

@edgeOperator

用于声明一个方法作为边操作函数。

import { edgeOperator } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @edgeOperator()
  addEdge(sourceId: string, targetId: string) {
    return [{
      type: 'add',
      edge: {
        id: generateId(),
        source: sourceId,
        target: targetId,
        type: 'default'
      }
    }]
  }
}

@edgePipe

用于声明一个方法作为边操作管道。

import { edgePipe } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @edgePipe()
  validateEdgeOperation() {
    return {
      preOperation: () => filter((operation) => {
        if (operation.type === 'add') {
          return this.validateEdge(operation.edge)
        }
        return true
      })
    }
  }
}

插件相关装饰器

@config

自动绑定配置管理和生命周期函数。

import { config } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @config()
  config = {
    theme: 'light',
    showGrid: true,
    gridSize: 20
  }

  // 配置会自动在 onInit 和 onConfigChange 时更新
}

@register

用于将插件的属性注册到引擎中,使其他插件可以通过 inject 访问。

import { register } from '@knotx/decorators'

class HistoryPlugin extends BasePlugin {
  @register('canUndo')
  canUndo = false

  @register('canRedo')
  canRedo = false

  @register('history')
  get history() {
    return this.historyStack
  }
}

@tool

用于装饰插件中的工具函数,使其能被引擎和其他插件调用。

import { tool } from '@knotx/decorators'

class MathPlugin extends BasePlugin {
  @tool('计算两点距离', {
    type: 'object',
    properties: {
      x1: { type: 'number', description: '第一个点的 X 坐标' },
      y1: { type: 'number', description: '第一个点的 Y 坐标' },
      x2: { type: 'number', description: '第二个点的 X 坐标' },
      y2: { type: 'number', description: '第二个点的 Y 坐标' }
    },
    required: ['x1', 'y1', 'x2', 'y2']
  })
  calculateDistance(params: { x1: number, y1: number, x2: number, y2: number }) {
    const dx = params.x2 - params.x1
    const dy = params.y2 - params.y1
    return Math.sqrt(dx * dx + dy * dy)
  }
}

参数

  • description: string - 工具函数描述
  • parameters: Schema - 参数的 JSON Schema 定义

@observable

创建响应式属性,支持数据绑定和变更监听。

import { observable } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @observable()
  selectedNodes: string[] = []

  @observable()
  zoomLevel = 1

  updateSelection(nodeIds: string[]) {
    this.selectedNodes = nodeIds // 自动触发变更通知
  }
}

生命周期装饰器

@OnInit

在插件初始化时调用。

import { OnInit } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @OnInit
  initialize(config: PluginConfig) {
    console.log('Plugin initialized with config:', config)
    this.setupEventListeners()
  }
}
@OnDestroy

在插件销毁时调用。

import { OnDestroy } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @OnDestroy
  cleanup() {
    console.log('Plugin destroyed')
    this.clearEventListeners()
  }
}
@OnConfigChange

在插件配置变更时调用。

import { OnConfigChange } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @OnConfigChange
  handleConfigChange(newConfig: PluginConfig) {
    console.log('Config changed:', newConfig)
    this.applyNewConfig(newConfig)
  }
}

引擎相关装饰器

@inject

用于注入引擎变量或其他插件的数据。

import { inject } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  // 注入引擎变量
  @inject.nodes()
  nodes: Node[] = []

  // 注入引擎方法
  @inject.getNodeById()
  getNodeById!: (id: string) => Node | undefined

  // 注入其他插件的数据
  @inject.history.canUndo()
  canUndo = false

  // 使用选择器注入特定数据
  @inject.nodes((nodes: Node[]) => nodes.filter(n => n.selected))
  selectedNodes: Node[] = []
}

使用方式

  • @inject.property() - 注入引擎变量
  • @inject.property(selector) - 注入引擎变量并使用选择器
  • @inject.pluginName.property() - 注入插件变量
  • @inject.methodName() - 注入引擎方法

@subscribe

用于订阅引擎变量或其他插件的数据变化。

import { subscribe } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  // 订阅引擎变量
  @subscribe.nodes()
  handleNodesChange(nodes: Node[]) {
    console.log('Nodes changed:', nodes)
    this.updateUI(nodes)
  }

  // 订阅其他插件的数据
  @subscribe.history.canUndo()
  handleUndoStateChange(canUndo: boolean) {
    this.updateUndoButton(canUndo)
  }
}

层相关装饰器

@layer

用于声明方法所属的渲染层级。

import { Layer } from '@knotx/core'
import { layer } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @layer(Layer.BACKGROUND)
  renderBackground() {
    return (
      <rect width="100%" height="100%" fill="#f0f0f0" />
    )
  }

  @layer(Layer.FOREGROUND, 100)
  renderOverlay() {
    return (
      <div className="overlay">
        Overlay content
      </div>
    )
  }
}

参数

  • layer: Layer - 层级枚举值
  • offset?: number - 层级偏移值

@panel

用于创建面板组件。

import { panel } from '@knotx/decorators'

class MyPlugin extends BasePlugin {
  @panel('top', { x: 10, y: 10 })
  renderToolbar() {
    return (
      <div className="toolbar">
        <button>Save</button>
        <button>Load</button>
        <button>Export</button>
      </div>
    )
  }

  @panel('bottom-right')
  renderStatus() {
    return (
      <div className="status">
        Ready
      </div>
    )
  }
}

参数

  • position: Position - 面板位置('top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right')
  • offset?: PanelOffset - 面板偏移
    • x?: number - X 轴偏移
    • y?: number - Y 轴偏移

文件目录结构

src/
├── index.ts                 # 主导出文件
├── internal.ts             # 内部工具函数
├── edge/                   # 边相关装饰器
│   ├── index.ts           # 边模块导出
│   ├── edgeType.ts        # 边类型装饰器
│   ├── edgeOperator.ts    # 边操作装饰器
│   └── edgePipe.ts        # 边管道装饰器
├── engine/                 # 引擎相关装饰器
│   ├── index.ts           # 引擎模块导出
│   ├── inject/            # 注入装饰器
│   │   ├── index.ts       # 注入模块导出
│   │   ├── inject-data.ts # 数据注入实现
│   │   ├── inject-decorator.ts # 注入装饰器实现
│   │   ├── inject-method.ts # 方法注入实现
│   │   ├── inject-plugin.ts # 插件注入实现
│   │   ├── injectable.ts  # 可注入接口
│   │   ├── injectable-proxy.ts # 注入代理实现
│   │   ├── proxy.ts       # 代理对象
│   │   └── types.ts       # 类型定义
│   └── subscribe/         # 订阅装饰器
│       ├── index.ts       # 订阅模块导出
│       ├── proxy.ts       # 订阅代理对象
│       ├── subscribe-data.ts # 数据订阅实现
│       ├── subscribe-decorator.ts # 订阅装饰器实现
│       ├── subscribe-plugin.ts # 插件订阅实现
│       └── types.ts       # 类型定义
├── layer/                  # 层相关装饰器
│   ├── index.ts           # 层模块导出
│   ├── layer.ts           # 层装饰器
│   └── panel.tsx          # 面板装饰器
├── node/                   # 节点相关装饰器
│   ├── index.ts           # 节点模块导出
│   ├── nodeType.ts        # 节点类型装饰器
│   ├── nodeOperator.ts    # 节点操作装饰器
│   └── nodePipe.ts        # 节点管道装饰器
└── plugin/                 # 插件相关装饰器
    ├── index.ts           # 插件模块导出
    ├── config.ts          # 配置装饰器
    ├── lifecycle.ts       # 生命周期装饰器
    ├── observable.ts      # 响应式装饰器
    ├── register.ts        # 注册装饰器
    └── tool.ts            # 工具函数装饰器

依赖关系

对等依赖 (Peer Dependencies)

  • @knotx/jsx - Knotx JSX 运行时支持

主要依赖 (Dependencies)

  • @knotx/core - Knotx 核心库
  • jsonschema - JSON Schema 验证库
  • lodash-es - 实用工具函数库
  • rxjs - 响应式编程库

许可证

MIT License

贡献指南

欢迎提交 Issue 和 Pull Request。在提交代码前,请确保:

  1. 代码符合项目的 ESLint 规则
  2. 通过 TypeScript 类型检查
  3. 添加必要的测试用例
  4. 更新相关文档

更多信息