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

@axhub/annotation

v1.0.5

Published

Read-only annotation runtime for Axhub prototype pages.

Readme

@axhub/annotation

@axhub/annotation 是一个面向原型页面的只读标注展示包,负责加载标注数据并用页面 marker 与点击后的标注气泡渲染出来。

功能边界

适合:

  • 已经有标注数据,希望在页面运行时展示
  • 需要同时支持 React 组件接入和实例化接入
  • 需要一套统一的 JSON 数据源,同时兼容不同加载方式

不适合:

  • 浏览器内编辑、保存、回写标注
  • 扫描页面自动生成标注数据
  • 把 editor / devtools 能力当成稳定公开接口

快速开始

最小 React 示例,直接把同一份 JSON 导入到 TS:

import { AnnotationViewer, type AnnotationSourceDocument } from '@axhub/annotation';
import annotationSource from './annotation-source.json';

const source = annotationSource as AnnotationSourceDocument;

export function DemoPage() {
  return (
    <AnnotationViewer
      source={source}
      defaultVisible
    />
  );
}

如果宿主需要延迟组装数据,可以传函数:

import { AnnotationViewer, type AnnotationSourceDocument } from '@axhub/annotation';
import annotationSource from './annotation-source.json';

function loadSource(): AnnotationSourceDocument {
  return annotationSource as AnnotationSourceDocument;
}

export function DemoPage() {
  return <AnnotationViewer source={loadSource} defaultVisible />;
}

运行时依赖:

  • 宿主提供 React 18
  • 宿主提供 ReactDOM 18
  • Ant Design 运行时样式与组件依赖由 @axhub/annotation 包内打包携带
  • 页面里能通过 ElementLocator 找到目标元素

推荐接入方式

推荐只维护一套 JSON 数据源,推荐 wire format 为 AnnotationSourceDocument。运行时不再按 URL 请求 JSON;请把 annotation-source.json 通过静态 import 或宿主内部函数组装进页面代码。

推荐目录结构:

demo-page/
├── index.tsx
├── annotation-source.json
└── assets/
    ├── hero-card.png
    └── order-table.png

推荐 JSON 示例:

{
  "documentVersion": 1,
  "format": "axhub-annotation-source",
  "data": {
    "version": 2,
    "prototypeName": "ref-app-home",
    "pageId": "home",
    "updatedAt": 1710000000000,
    "nodes": [
      {
        "id": "hero-card",
        "index": 1,
        "title": "Hero Card",
        "locator": {
          "selectors": ["[data-testid=\"hero-card\"]"],
          "fingerprint": "div|hero-card",
          "path": [0, 1, 0]
        },
        "aiPrompt": "说明首屏卡片的结构和状态",
        "annotationText": "",
        "hasMarkdown": true,
        "color": "#1677ff",
        "images": [],
        "createdAt": 1710000000000,
        "updatedAt": 1710000000000
      }
    ]
  },
  "markdownMap": {
    "hero-card": "# Hero Card\n\n这里放该节点的详细说明。"
  },
  "assetMap": {},
  "directory": {
    "nodes": [
      {
        "type": "folder",
        "id": "guide",
        "title": "演示目录",
        "defaultExpanded": true,
        "children": [
          {
            "type": "route",
            "id": "route-empty",
            "title": "切换缺省态",
            "route": "orders:empty",
            "payload": { "status": "empty" }
          },
          {
            "type": "link",
            "id": "external-doc",
            "title": "外部文档",
            "href": "https://example.com/docs",
            "target": "blank"
          },
          {
            "type": "markdown",
            "id": "readme",
            "title": "目录说明",
            "markdown": "# 目录说明\n\n这里会在目录左侧阅读面板中展示。"
          }
        ]
      }
    ]
  }
}

AnnotationNode 关键字段建议这样理解:

  • id:节点稳定标识,建议长期不变
  • annotationText:短标注,仅用于 hasMarkdown: false 的节点
  • hasMarkdown:是否使用 Markdown 文档作为唯一标注正文
  • title:节点标题,建议直接写入数据源,不依赖运行时补全

JSON 目录

directory.nodes 用于驱动“原型目录”面板。目录支持四类节点:

  • folder:多级文件夹,defaultExpanded 控制初始展开。
  • route:点击时调用 options.onDirectoryRoute(node),运行时不强制跳转。
  • linktarget: "blank" 新窗口打开,target: "self" 当前页打开。
  • markdown:使用内联 markdown,点击后在目录左侧打开阅读面板。

路由节点的推荐做法是让宿主自行决定行为:可以切 SPA 路由、改 URL、切换页面状态,或替换数据源展示缺省/异常/活动态。

  • controls:节点关联的属性调整项,属于标注内容的一部分
  • markdownMap[nodeId]:Markdown 标注正文,仅用于 hasMarkdown: true 的节点
  • images:节点引用的资源文件名,仅用于 hasMarkdown: false 的节点
  • assetMap[filename]:资源文件名到 URL 的映射

hasMarkdown: true 与短标注/图片展示互斥:运行时会直接显示 markdownMap[nodeId] 的内容,不再显示 annotationText,也不会展示该节点的 images。需要配图时请把图片语法写进 Markdown 正文。

更详细的目录、字段和加载说明见 推荐 JSON 加载

全局数据快照

运行时加载成功后,会在页面全局输出 window.__AXHUB_ANNOTATION_SOURCE__

interface AnnotationSourceRuntimeSnapshot {
  directory: AnnotationDirectory | null;
  nodes: AnnotationNode[];
}

这个快照用于给宿主、调试工具或 Agent 读取当前原型目录和全部标注节点。它会在 viewer 停止、卸载或没有可展示内容时清除;消费方应把它当作只读数据,不要依赖修改该对象来影响运行时。

兼容接入方式

当前包仍兼容现有对象直传和 AnnotationStorage 模式。

legacy AnnotationStorage 示例:

import { createAnnotationViewer, type AnnotationStorage } from '@axhub/annotation';

const storage: AnnotationStorage = {
  load: async () => null,
  loadAnnotationsMd: async () => null,
  loadMarkdown: async (_nodeId) => null,
  getAssetUrl: (filename) => `/runtime/assets/${filename}`,
};

const viewer = createAnnotationViewer({
  prototypeName: 'ref-app-home',
  pageId: 'home',
  storage,
});

void viewer.start();

兼容模式仍可继续使用,但不再是主推荐路径。字段映射和迁移方式见 Legacy MD / Storage 兼容说明

公开接口导航

当前“只读标注能力”建议直接使用这些根入口接口:

  • AnnotationViewer
  • createAnnotationViewer
  • AnnotationSourceInput
  • AnnotationSource
  • AnnotationSourceDocument
  • AnnotationData
  • AnnotationNode
  • AnnotationSourceRuntimeSnapshot
  • AnnotationViewerOptions
  • AnnotationViewerApi
  • ElementLocator
  • parseAnnotationsMarkdown
  • parseAnnotationMarkdownRecords
  • serializeAnnotationsMarkdown
  • buildAnnotationPrompt
  • AnnotationStorage

详细签名和最小示例见 API Reference

深入文档