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.18

Published

Read-only annotation runtime for Axhub prototype pages.

Downloads

3,090

Readme

@axhub/annotation

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

它可以脱离 axhub-make 单独集成到宿主页面:React 18 项目使用 AnnotationViewercreateAnnotationViewer 的 ESM 入口;普通 HTML、React 17、Vue、Angular 或托管注入场景使用包内自带的 standalone browser bundle。

功能边界

适合:

  • 已经有标注数据,希望在页面运行时展示
  • 需要同时支持 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 />;
}

本地演示

包内提供两个可预览示例,统一放在 examples/

  • examples/react:React 宿主示例,使用 AnnotationViewer 组件接入。
  • examples/html:普通 HTML 宿主示例,页面主体用原生 DOM,通过 window.AxhubAnnotation.createAnnotationViewer 接入自托管 browser bundle。

启动命令:

pnpm examples:react
pnpm examples:html

两个示例共享 examples/shared/annotation-source.json,覆盖 Markdown 标注、短标注、多颜色筛选、同一节点多条标注、状态标注 controls、原型目录 route/markdown/link 等能力。

ESM 运行时依赖:

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

standalone browser bundle 不要求宿主提供 React、ReactDOM 或 antd。pnpm build 会生成 dist/browser/axhub-annotation.global.js 和 sourcemap,用户可以把该文件从 npm 包中复制到自己的静态资源服务器、内网 CDN、OSS 或任意 web server 后用普通 <script> 注入。

<script src="/static/vendor/axhub-annotation/axhub-annotation.global.js"></script>
<script>
  const viewer = window.AxhubAnnotation.createAnnotationViewer({
    source: () => fetch('/annotation-source.json').then((response) => response.json()),
  });

  void viewer.start();
</script>

推荐接入方式

推荐只维护一套 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",
  "presentation": {
    "layerSelectors": [".example-modal-layer[data-open=\"true\"]"]
  },
  "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这里会在目录左侧阅读面板中展示。"
          }
        ]
      }
    ]
  }
}

presentation.layerSelectors 可声明当前页面的前景层根节点;打开层存在时,仅展示该层内部目标的 marker 和已选标注气泡。选择器应匹配包含弹窗内容的活动容器。

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

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

JSON 目录

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

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

markdownPath 可以作为 Make 原型的源文件约定,例如 docs/prd-03-status.md,但 @axhub/annotation 运行时只消费已经内联好的 markdown 正文,不会按路径 fetch .md 文件,也不会内置文档编辑按钮。Make 的文档编辑入口由批注工具按当前选中的目录 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[];
  presentation?: AnnotationSourcePresentation;
  source?: {
    root?: string;
    manifest?: string;
  };
}

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

当发布 HTML 勾选“带源码”且页面实际使用了 @axhub/annotation 时,发布产物会注入 sourceReference,快照会额外包含 source,其中 manifest 指向发布包内的 source/manifest.json。普通宿主不需要手写这个字段。

运行时控制器与侧边栏注入

viewer 启动后会同时暴露 window.__AXHUB_ANNOTATION_RUNTIME__,用于宿主或托管页注入脚本在页面运行后读取运行时状态、调整工具栏配置,并向侧边栏注入自定义动作。

const runtime = window.__AXHUB_ANNOTATION_RUNTIME__;
const action = document.querySelector('#my-annotation-action');

if (action) {
  runtime?.configure({
    toolbarAutoHide: false,
    toolbarActions: {
      title: '安全提示',
      content: action,
    },
  });
}

自定义动作固定显示在侧边栏“标注配置”按钮之后、“设置”按钮之前。toolbarActions 只接受 { title?, content } 或数组;title 可选,传入时运行时统一套和“原型目录 / 设置”一致的 Tooltip,不传时只渲染 contentcontent 可以是 DOM Element 或 React 节点,宿主自己负责图标、点击和业务弹窗。React 宿主如果需要根据当前页面或标注数量渲染,可继续使用 AnnotationViewerOptions.renderToolbarActions(context) 或全局 configure({ renderToolbarActions })

runtime.metadata / runtime.getMetadata() 会返回 packageNameruntimeVersionfeatures、当前页面、当前页标注数量、侧边栏显示状态与是否已注册自定义动作,可用于发布前检测或注入脚本识别。该控制器只提供通用运行时协议;Axhub 托管安全提示、举报、业务 URL、埋点和弹窗内容应由宿主或注入脚本自行实现。

批注适配约定

标注运行时使用 #__axhub_annotation_host__ 的 open Shadow Root。为了让 axhub-genie-editor 可以稳定批注标注组件内部内容,标注组件会在明确可批注的内部元素上声明:

data-axhub-annotation-comment-target="true"

当前声明范围包括目录节点按钮、目录阅读器的正文 Markdown、目录阅读器右侧 TOC 按钮、标注气泡正文 Markdown。批注侧只在 #__axhub_annotation_host__ 的 Shadow 命中栈内识别这个属性;如果命中的是被声明元素的子节点,会回到最近的声明祖先。不要依赖批注侧按尺寸、样式或 DOM 层级猜测具体目标。

兼容接入方式

当前包仍兼容现有对象直传和 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
  • AnnotationRuntimeController
  • AnnotationRuntimeMetadata
  • AnnotationRuntimeConfigureOptions
  • AnnotationToolbarActionItem
  • AnnotationToolbarActionsContent
  • AnnotationToolbarActionsRenderer
  • AnnotationToolbarActionsContext
  • AnnotationViewerOptions
  • AnnotationViewerApi
  • ElementLocator
  • parseAnnotationsMarkdown
  • parseAnnotationMarkdownRecords
  • serializeAnnotationsMarkdown
  • buildAnnotationPrompt
  • AnnotationStorage

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

深入文档