a5faec5abf
下游 Vite / Rollup / TypeScript 靜態 ESM 解析需要真正之 `export`
關鍵字;原 UMD-ish(module.exports + globalThis)對 ESM 消費端
仍須走副作用導入 + globalThis 取值之 workaround。
於檔尾既有 CJS / globalThis 兩塊後再加 `export { createCjkAutospace };
順序刻意如此,讓串接端(IIFE 函式體內不能有 module-level export)
只需以 `sed '/^export {/d'` 剝最後一行即安全。
four-form export 同時支援:ESM named import / CommonJS require /
globalThis / IIFE 串接(後者需剝 export 行)。README 同步補上。
83 lines
5.1 KiB
Markdown
83 lines
5.1 KiB
Markdown
# cjk-autospace
|
||
|
||
CJK ↔ Latin / 數字 / 標點 / 引號 / 括號 / 運算子等邊界之自動間距 shim。Pangu.js v7.2.1 規則之 ES5 端口,加上「跨樣式標籤透明 + 行內塊邊界」兩 pass 架構,再加 Pass C 長英文段 `<span lang>` 包裝(讓瀏覽器原生連字斷詞)。工廠模式,由消費端注入配置。
|
||
|
||
> **詳細文檔 + Changelog 位於 `docs` 分支**:架構解析、雙 pass 流程、整合範例見 [`index.html`](https://git.commilitia.net/admin/cjk-autospace/src/branch/docs/index.html);變更記錄見 [`CHANGELOG.html`](https://git.commilitia.net/admin/cjk-autospace/src/branch/docs/CHANGELOG.html)。本機並列檢出:`git worktree add ../cjk-autospace-docs docs`。
|
||
|
||
## API
|
||
|
||
```js
|
||
const autospace = createCjkAutospace({
|
||
pillSelector: "code, kbd, .your-pill-class",
|
||
});
|
||
autospace.apply(document.body);
|
||
```
|
||
|
||
回傳 `{ apply(root?) }`。冪等:在已注入 marker 之 DOM 上重跑會跳過既有 `.cjk-autospace`。完整選項見 `cjk-autospace.d.ts`。
|
||
|
||
## CSS 需求
|
||
|
||
```css
|
||
.cjk-autospace {
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
/* 視覺寬度由消費端決定,例如 0.25em via inline-block + width */
|
||
}
|
||
```
|
||
|
||
`user-select: none` 讓選取與剪貼板跳過 marker;marker 內含真實 ASCII space(layout 視為 whitespace:行末 collapse、容許換行、justify 可拉伸)。
|
||
|
||
## 標籤三分類
|
||
|
||
- **STYLE_INLINES**(`<strong>` / `<em>` / `<a>` / `<b>` / `<i>` / `<u>` / `<s>` / `<mark>` / `<ins>` / `<del>` / `<sub>` / `<sup>` / `<small>` / `<abbr>` / `<cite>` / `<dfn>` / `<q>` / `<span>` / `<var>` / `<samp>` / `<time>` / `<bdo>` / `<bdi>` / `<ruby>` / `<rb>` / `<rt>` / `<rp>` / `<wbr>`)— shim 透明走過。跨樣式之 Pangu 邊界(如 `<strong>是</strong> Neovim`)由 Pass A 在剝離後識別。
|
||
- **PILL**(由 `pillSelector` 指定,預設 `code, kbd`)— 行內塊。邊界由 Pass B 處理,與內容鄰接(CJK / 字母數字)即插 marker。
|
||
- **BLOCK**(`<p>` / `<div>` / `<h1>`–`<h6>` / `<li>` / `<pre>` / `<table>` / `<br>` / `<hr>` / …)— 段落級。Pass A 把它們當作 run 邊界,子 block 各自一次。
|
||
|
||
## 三 pass
|
||
|
||
- **Pass A — per-block Pangu on tag-stripped text**:對每個 BLOCK 走 DFS 收集邏輯文本(STYLE 透明、PILL 與子 BLOCK 中斷 run、既有 marker 也中斷),整段套 `panguSpace`,把 MARK 反映射回 textNode/offset。MARK 對應原文若是單 ASCII space 則 strip 後插 marker,否則純插。actions 倒序執行確保前面偏移不被後面動作影響。
|
||
- **Pass B — pill boundary**:對每個 PILL 透過 STYLE 鏈遞迴找邏輯鄰字(`adjacentLogicalChar`),鄰字若是 CJK / 字母數字直接插 marker;若是 1 個 ASCII space 且另一側為內容字則 strip 後插 marker;其餘(標點 / 多空格 / 換行 / 既有 marker)跳過。
|
||
- **Pass C — long English word wrap**(**預設啟用**,`longWordWrap: false` 顯式關閉):將文本節點內所有 `[A-Za-z]{N,}`(預設 `N=6`)之長英文段包進 `<span lang="en">`。冪等:parent 已為 `<span lang>` 直接跳過。**連字符不在 DOM**,由瀏覽器 `hyphens: auto` 在斷行時純視覺渲染 → 選取 / 複製返回原文無污染。需消費端加 CSS:
|
||
|
||
```css
|
||
[lang|="en"] {
|
||
hyphens: auto;
|
||
-webkit-hyphens: auto;
|
||
hyphenate-limit-chars: 6 3 3; /* 詞長 / 斷點前 / 斷點後最少字符 */
|
||
}
|
||
```
|
||
|
||
不加 CSS 則 span 為惰性(DOM 變更但無視覺效果)。
|
||
|
||
## 配置選項
|
||
|
||
| 選項 | 預設 | 說明 |
|
||
|---|---|---|
|
||
| `pillSelector` | `"code, kbd"` | 行內塊 CSS 選擇器 |
|
||
| `styleInlines` | 預設樣式標籤集 | tagName 大寫之陣列 |
|
||
| `blockTags` | 預設段落標籤集 | tagName 大寫之陣列 |
|
||
| `skipTags` | mono / form / script / style | tagName 大寫之陣列;整 subtree skip |
|
||
| `autospaceClass` | `"cjk-autospace"` | marker span class 名 |
|
||
| `skipAttribute` | `"data-md-key"` | 任一祖先帶此屬性即整 subtree skip |
|
||
| `isSkipped` | (無) | 自訂 skip callback;先於內建判定檢查 |
|
||
| `longWordWrap` | `true`(預設啟用) | Pass C 開關。傳 `false` 顯式關閉;`{minLength, lang}` 自訂;`true` / 省略等同 `{minLength: 6, lang: "en"}` |
|
||
|
||
## 模組形式
|
||
|
||
四種消費場景並存:
|
||
|
||
- **ES module / TypeScript**:`import { createCjkAutospace } from "./cjk-autospace.js"`(檔尾 `export { createCjkAutospace }`,配 `cjk-autospace.d.ts`)
|
||
- **CommonJS / Node**:`require("./cjk-autospace.js").createCjkAutospace`(檔尾 `module.exports`)
|
||
- **Browser global**:載入後可 `globalThis.createCjkAutospace`
|
||
- **IIFE 串接**:把本檔內容 `cat` 進單一閉包(如 Claude 模板 `build.sh` / Nvim peek build hook)— `export {…}` 為 ESM module-level 語法,串入函式體內會語法錯誤,串接端須剝掉那行:
|
||
|
||
```sh
|
||
sed '/^export[[:space:]]*{/d' cjk-autospace.js
|
||
```
|
||
|
||
其餘 `module.exports` / `globalThis` 兩塊在閉包內安全(`typeof` 檢查不會 throw、globalThis 賦值無副作用)。
|
||
|
||
## 授權
|
||
|
||
基於 Pangu.js v7.2.1 的規則表 port([原始項目](https://github.com/vinta/pangu.js) MIT)。
|