npm package: @mybricks/dom-to-figma-clipboard
Description: 将浏览器 DOM 直接转换为 Figma 剪贴板协议，粘贴即可生成设计稿
Latest version: 0.1.0

# dom-to-figma

将浏览器 DOM 直接转换为 Figma 剪贴板协议，粘贴即可生成设计稿，**无需 Figma 插件**。

## 安装

```bash
npm install
```

> 需要 Node.js ≥ 14 或现代浏览器（Chrome 90+）。

## 快速上手

### 方式一：npm require（webpack / Node.js 环境）

```js
const { domToFigmaClipboard } = require('dom-to-figma');

// el 是目标 DOM 元素
const html = await domToFigmaClipboard(el, {
  styleTagId: 'my-style-tag',   // 可选，传入声明层 <style> id 可提升样式精度
  fontCtx: fontCtx,             // 可选，见「字体」章节
});

// 写入剪贴板后前往 Figma Cmd+V 粘贴
await writeHtmlToClipboard(html);
```

### 方式二：浏览器 script 标签注入（控制台调试）

把 `src/` 目录下的 JS 文件逐个以 `<script>` 注入页面（或在控制台 fetch 后 eval），最后注入 `index.js`：

```js
// 注入顺序（浏览器 eval 模式）
// dom-helpers.js → css-parsers.js → style-builder.js → layout-utils.js
// → node-builder.js → image-inline.js → src/dom-to-json.js
// → src/ir-to-figma-clipboard.js（需提前加载 pako / kiwi-schema）
// → index.js

// 注入完成后直接调用：
const html = await window.domToFigmaClipboard(document.querySelector('#my-el'));
```

## API

### `domToFigmaClipboard(el, options?)` → `Promise<string>`

| 参数 | 类型 | 说明 |
|------|------|------|
| `el` | `Element` | 目标 DOM 元素 |
| `options.styleTagId` | `string?` | 声明层 `<style>` 标签 id，有则传，没有也能工作 |
| `options.fontCtx` | `object?` | opentype 字体上下文（见下方「字体」章节） |
| `options.componentLibraryEnabled` | `boolean?` | 是否输出组件库节点，默认 `false` |

返回可直接写入剪贴板的 HTML 字符串。

### `domToFigmaJson(el, options?)` → `Promise<object>`

只返回中间 IR JSON，不生成剪贴板协议，适合调试或二次加工。

## 字体

调用 `domToFigmaClipboard` 时**字体会自动加载**，无需手动传入任何参数。

加载来源优先级：
1. **系统本地字体**（Chrome 103+，调用时浏览器会弹出权限请求）
2. **`window.__PINGFANG_FONT_URL__`**（可提前设置为可访问的字体文件 URL，作为兜底）
3. 以上均失败 → 跳过字体加载，Figma 里文本需**双击**后才显示

```js
// 方式一：什么都不用做，字体自动加载
const html = await domToFigmaClipboard(el);

// 方式二：提前设置字体 URL（推荐在生产环境中使用，避免依赖本地字体权限）
window.__PINGFANG_FONT_URL__ = 'https://your-cdn.com/fonts/PingFangSC-Regular.ttf';
const html = await domToFigmaClipboard(el);

// 方式三：提前预热字体（避免第一次导出时的等待），在页面初始化时调用
import { preloadFont } from 'dom-to-figma';
preloadFont(); // 后台加载，不需要 await

// 方式四：完全跳过字体（明确知道不需要文字立即显示时）
const html = await domToFigmaClipboard(el, { fontCtx: null });
```

## 写入剪贴板

```js
async function writeHtmlToClipboard(html) {
  // 优先使用 Clipboard API
  if (navigator.clipboard && window.ClipboardItem) {
    await navigator.clipboard.write([
      new ClipboardItem({
        'text/html': new Blob([html], { type: 'text/html' }),
        'text/plain': new Blob([html], { type: 'text/plain' }),
      })
    ]);
    return;
  }
  // 降级：execCommand
  const listener = (e) => {
    e.preventDefault();
    e.clipboardData.setData('text/html', html);
    e.clipboardData.setData('text/plain', html);
  };
  document.addEventListener('copy', listener);
  document.execCommand('copy');
  document.removeEventListener('copy', listener);
}
```

## 文件结构

```
dom-to-figma/
├── index.js                   # 包入口，暴露公共 API
├── package.json
├── README.md
└── src/
    ├── dom-to-json.js         # DOM → IR JSON（含图片内联）
    ├── dom-helpers.js         # Shadow DOM / 坐标系工具
    ├── css-parsers.js         # CSS 解析（渐变、阴影、SVG 路径…）
    ├── style-builder.js       # 样式 JSON 构建
    ├── layout-utils.js        # Flex / Grid 布局处理
    ├── node-builder.js        # 节点构建（伪元素、形状…）
    ├── image-inline.js        # 图片 URL → base64 内联
    ├── font-loader.js         # 自动加载 PingFang SC 字体
    ├── ir-to-figma-clipboard.js  # IR JSON → Figma 剪贴板二进制
    ├── figma-schema-data.js   # Figma kiwi schema（预编译数据）
    └── svg-pathdata-umd.js    # SVG 路径处理工具
```

## 注意事项

- 必须在**浏览器**中运行，依赖 `getBoundingClientRect`、`getComputedStyle` 等 DOM API。
- 图片内联会发起跨域请求，确保服务端允许 CORS 或图片与页面同域。
- Figma 剪贴板协议基于逆向工程，Figma 更新版本后可能需要同步维护 `figma-schema-data.js`。