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

a2ui-auto-layout

v0.2.3

Published

A2UI 0.9 布局编辑器 — 单包,setup.css(Less + scoped Tailwind 工具类)全局样式

Readme

a2ui-auto-layout

A2UI 0.9 可视化布局编辑器 — 单 npm 包,提供布局编辑、Card Studio 卡片编辑、声明式 Surface 渲染与 Registry 注册能力。

  • 布局编辑器 A2UILayoutEditor:资源库 + 画布 + 检查器,输出 A2UIDocument
  • 卡片编辑器 A2UICardEditor:编辑声明式卡片 Surface,输出 CardStudioEnvelope
  • Surface 渲染 AdaptiveDeclarativeSurface 等:卡片 JSON 纯回显
  • 样式 全局 setup.css(Less 层 + 作用域化 Tailwind 工具类),宿主入口引入一次即可;无需在宿主配置 Tailwind 扫描本包;utility 不泄漏到编辑器外

环境要求

| 依赖 | 版本 | |------|------| | react / react-dom | ^18.0.0 \|\| ^19.0.0(peer) | | 构建工具 | Vite / Webpack / Umi 等支持 ESM 的 bundler |

安装

pnpm add a2ui-auto-layout
# 或 npm install a2ui-auto-layout

在应用入口引入全局样式(npm 消费路径下 必须,否则编辑器与 Surface 样式会缺失):

import 'a2ui-auto-layout/setup.css';

TypeScript 宿主无需额外配置:package.json 的 exports / typesVersions 已为 setup.css 提供类型。若旧版 bundler 仍报「找不到模块」,在宿主增加 declare module 'a2ui-auto-layout/setup.css';(见 PUBLISHING.md)。

再按需 import 组件:

import {
  A2UILayoutEditor,
  A2UICardEditor,
  AdaptiveDeclarativeSurface,
  createA2UIRegistry,
  registerDeclarativeCardFromEnvelope,
} from 'a2ui-auto-layout';

快速开始

布局编辑器

编辑器默认占满父容器,宿主需为父级提供明确高度(如 h-screen / height: 100vh):

import { A2UILayoutEditor, createA2UIRegistry } from 'a2ui-auto-layout';
import 'a2ui-auto-layout/setup.css';

const registry = createA2UIRegistry();

export function LayoutStudioPage() {
  return (
    <div className="flex h-screen flex-col">
      <div className="min-h-0 flex-1">
        <A2UILayoutEditor
          registry={registry}
          className="h-full min-h-0"
          onEvent={(payload) => console.log('surface event', payload)}
          onSave={(doc) => console.log('saved', doc)}
        />
      </div>
    </div>
  );
}

上述示例 registry 为空,侧栏无业务卡片。将卡片编辑器产出的 CardStudioEnvelope 注册进 registry 后,资源库即可拖入,见下文 Registry 配置。

卡片编辑器

A2UICardEditor 无内置顶栏,保存 / 导入等操作由宿主通过 ref 触发:

import { useRef } from 'react';
import {
  A2UICardEditor,
  type A2UICardEditorHandle,
  type CardStudioEnvelope,
} from 'a2ui-auto-layout';
import 'a2ui-auto-layout/setup.css';

export function CardStudioPage({ envelope }: { envelope: CardStudioEnvelope }) {
  const cardRef = useRef<A2UICardEditorHandle>(null);

  return (
    <div className="flex h-screen flex-col">
      <header className="flex gap-2 border-b p-2">
        <button type="button" onClick={() => cardRef.current?.save()}>
          保存
        </button>
        <button type="button" onClick={() => cardRef.current?.openComposerImport()}>
          导入 Composer JSON
        </button>
      </header>
      <div className="min-h-0 flex-1">
        <A2UICardEditor
          ref={cardRef}
          initialEnvelope={envelope}
          categoryOptions={[{ key: 'card', label: '卡片' }]}
          className="h-full min-h-0"
        />
      </div>
    </div>
  );
}

Registry 配置(布局资源库)

布局编辑器左侧「资源库」的可拖模板来自 A2UIRegistry。宿主通常只有卡片编辑器产出的 CardStudioEnvelope(与 A2UICardEditor 的 onSave / exportEnvelope() 同形)。

推荐:一行信封数组(0.2.3+):

import { useEffect, useState } from 'react';
import { A2UILayoutEditor, type CardStudioEnvelope } from 'a2ui-auto-layout';
import 'a2ui-auto-layout/setup.css';

export function LayoutStudioPage() {
  const [cards, setCards] = useState<CardStudioEnvelope[]>([]);

  useEffect(() => {
    fetch('/api/cards').then((r) => r.json()).then(setCards);
  }, []);

  return (
    <A2UILayoutEditor
      cardEnvelopes={cards}
      className="h-full min-h-0"
      mode={{ workMode: 'edit', layoutMode: 'flow' }}
      onSave={(doc) => saveLayout(doc)}
    />
  );
}

cardEnvelopes 会自动:

  • 调用 createA2UIRegistryFromEnvelopes 注册资源库
  • 从 template.category 推导 templateGroups(可选手动覆盖)

也支持纯 surface JSON({ components, data }),内部会 normalizeCardStudioEnvelope 容错。

高级:手动组装 registry(自定义合并逻辑时):

CardStudioEnvelope[](API / 本地存储)
        │
        ▼
createA2UIRegistryFromEnvelopes(envelopes)  或  registerDeclarativeCardFromEnvelope × N
        │
        ▼
<A2UILayoutEditor registry={registry} />

信封结构(CardStudioEnvelope):

{
  name: string;
  description: string;
  template: {
    id: string;
    component: string;       // 唯一键,同名 register 会覆盖
    category: string;        // 资源库分组,如 'card'
    icon?: string;
    defaultLayout?: Record<string, unknown>;
  };
  surface: {
    components: [...];
    data: Record<string, unknown>;
  };
  meta?: { savedAt?: string };
}

静态单卡(联调 / Test 页):

import { A2UILayoutEditor, type CardStudioEnvelope } from 'a2ui-auto-layout';

const smokeCard: CardStudioEnvelope = { /* 同上 */ };

export function LayoutStudioPage() {
  return (
    <A2UILayoutEditor
      cardEnvelopes={[smokeCard]}
      className="h-full min-h-0"
      mode={{ workMode: 'edit', layoutMode: 'flow' }}
    />
  );
}

生产:从 API 加载卡片列表:

import { useEffect, useState } from 'react';
import { A2UILayoutEditor, type CardStudioEnvelope } from 'a2ui-auto-layout';

export function LayoutStudioPage() {
  const [envelopes, setEnvelopes] = useState<CardStudioEnvelope[]>([]);

  useEffect(() => {
    fetch('/api/cards').then((r) => r.json()).then(setEnvelopes);
  }, []);

  const handleCardSave = (envelope: CardStudioEnvelope) => {
    setEnvelopes((prev) => {
      const component = envelope.template.component;
      const idx = prev.findIndex((e) => e.template.component === component);
      if (idx >= 0) {
        const next = [...prev];
        next[idx] = envelope;
        return next;
      }
      return [...prev, envelope];
    });
    // 同时 POST 到你的 API
  };

  return (
    <A2UILayoutEditor
      cardEnvelopes={envelopes}
      className="h-full min-h-0"
      resourceLibraryEmptyMessage="暂无卡片,请先在卡片编辑器创建"
    />
  );
}

卡片编辑器保存时与布局编辑器共用同一份 envelopes 状态;handleCardSave 传给 A2UICardEditor 的 onSave 即可,保存后资源库立即可拖。

运行时增量注册(不重建 registry 时):

registry.register(registerDeclarativeCardFromEnvelope(envelope));

| 项 | 说明 | |----|------| | createA2UIRegistry() 无参数 | 资源库为空(仅 PageRoot),侧栏显示「没有匹配的组件」 | | useBuiltinComponents: true | 合并内置 Dashboard 组件(与业务卡片并存,非默认推荐) | | templateGroups | 可选;控制资源库分组标题与顺序,由 template.category 匹配 | | API 返回纯 surface | 用 normalizeCardStudioEnvelope(json) 规范化后再注册 |

cardEnvelopes(0.2.3+)是推荐接入方式;createA2UIRegistryFromEnvelopes 与 registerDeclarativeCardFromEnvelope 供高级场景使用。

完整数据流、Umi 宿主与 Card Studio 联调见 宿主接入 §6 / §9。

工作模式

| 模式 | 典型场景 | 推荐 API | |------|----------|----------| | 编辑 | 配置台、Card Studio | A2UILayoutEditor / A2UICardEditor(默认) | | 预览 | 编辑器内交互验收 | ref.setWorkMode('preview') 或 Card setPreviewMode(true) | | 纯回显 | 业务详情页只读展示 | 布局:A2UILayoutEditor + showChrome={false} + preview;卡片:AdaptiveDeclarativeSurface |

预览 ≠ 纯回显:预览仍在编辑器壳内。布局若需零编辑 UI,见 宿主接入 §7.7 / §10。

纯回显示例

布局(编辑器壳内,快速接入):

import { A2UILayoutEditor, createA2UIRegistry, type A2UIDocument } from 'a2ui-auto-layout';
import 'a2ui-auto-layout/setup.css';

const registry = createA2UIRegistry();

export function LayoutDisplayPage({ document }: { document: A2UIDocument }) {
  return (
    <A2UILayoutEditor
      showChrome={false}
      className="h-full min-h-0"
      mode={{ workMode: 'preview', layoutMode: 'flow' }}
      document={document}
      registry={registry}
      onEvent={(payload) => console.log(payload)}
    />
  );
}

卡片 Surface(推荐生产路径):

import { AdaptiveDeclarativeSurface, ModalHostProvider } from 'a2ui-auto-layout';
import type { DeclarativeCardDocument } from 'a2ui-auto-layout';
import 'a2ui-auto-layout/setup.css';

export function CardDisplayPage({ surface }: { surface: DeclarativeCardDocument }) {
  return (
    <ModalHostProvider defaultModalMount="canvas">
      <AdaptiveDeclarativeSurface
        backend="hybrid"
        composerParity
        workMode="preview"
        root={surface.root}
        components={surface.components}
        data={surface.data}
        onSurfaceEvent={(name, payload) => console.log(name, payload)}
      />
    </ModalHostProvider>
  );
}

样式说明

| 项 | 说明 | |----|------| | 入口 | import 'a2ui-auto-layout/setup.css' — 唯一推荐的全局样式入口 | | 内容 | 编辑器主题、chrome、声明式 Surface、Composer parity、A2UI catalog 层 | | Tailwind | 工具类限定在 .a2ui-auto-layout-root 与 .a2ui-declarative-surface 内,不会作为全局 .flex / .bg-primary 泄漏到宿主 | | 宿主 reset | 编辑器壳内原生 button / input 有轻量 reset,减轻 Ant Design 等全局样式覆盖 | | 构建 | 源码 *.module.less → dist/setup.css;JS bundle 不含 CSS side-effect |

Umi + MFSU 宿主建议在 .umirc.ts 中排除预构建:

mfsu: { exclude: ['a2ui-auto-layout', '@a2ui/react', '@a2ui/web_core'] },

升级本包版本后清缓存:

pnpm exec rimraf src\.umi node_modules\.cache\mfsu

不要在宿主页面依赖 setup.css 泄漏的全局 utility;宿主自己的 .bg-primary / .hidden 与包内 utility 已隔离。setup.css 可放在宿主 global.less 末尾(推荐)或任意顺序(scope 后编辑器内部均生效)。

样式仍异常时,确认版本 ≥ 0.2.2、入口已 import setup.css、MFSU 已 exclude;更多排查见 宿主接入 §4。

容器尺寸约定

编辑器根节点使用 height: 100% + min-height: 0 填满父级。推荐宿主结构:

<div className="flex h-screen flex-col">
  {/* 可选:宿主顶栏 */}
  <div className="min-h-0 flex-1">
    <A2UILayoutEditor className="h-full min-h-0" /* ... */ />
  </div>
</div>

避免在 body 与编辑器之间产生双重滚动条。

主要导出

| 类别 | 符号 | |------|------| | 编辑器 | A2UILayoutEditor, A2UICardEditor | | Registry | cardEnvelopes, createA2UIRegistryFromEnvelopes, buildTemplateGroupsFromEnvelopes | | 渲染 | AdaptiveDeclarativeSurface, HybridDeclarativeSurface, OfficialDeclarativeSurface, ModalHostProvider | | 类型 | A2UIDocument, CardStudioEnvelope, A2UIEventPayload, EditorTheme | | 样式 | a2ui-auto-layout/setup.css(package export) |

完整 API 与 ref 方法见 DEVELOPMENT.md 附录 F。

本仓库开发

pnpm install
pnpm dev                 # build dist + 启动 demo → http://localhost:5173
pnpm build               # dist/index.js + dist/index.d.ts + dist/setup.css
pnpm test
pnpm lint
pnpm typecheck
pnpm prepublish:verify   # 发布前全量验证(lint / build / demo / smoke / leftovers)

demo/ 与 npm 宿主行为一致:只消费 dist/,不 alias 到 src/。修改 src/ 后需重新 pnpm build(或另开终端 pnpm build:watch)。

| 命令 | 用途 | |------|------| | pnpm check:demo | demo 生产构建 | | pnpm check:smoke | pack → 临时目录 npm install → Vite 构建(模拟 npm 消费者) | | pnpm check:publish | 产物体积、exports、CSS 抽检 |

发布(维护者)

npm login
pnpm prepublish:verify
pnpm release             # verify + npm publish --access public

详见 docs/PUBLISHING.md。

文档索引

| 文档 | 说明 | |------|------| | 宿主接入双编辑器 | 安装、样式、Registry、三种模式、纯回显、Umi FAQ | | 发布到 npm | 版本、验证门禁、smoke 测试 | | 开发文档 | 架构、本地调试、API 速查 | | AI 撰写 Surface | 声明式 JSON 编写指南(含 画布组件 JSON 约束规范) | | 声明式模式 | Row / Card / Chart 等布局模式 |

License

MIT