69f34413c9
對應 main 之 a5faec5。檔尾加 `export { createCjkAutospace }` 讓
Vite / Rollup / TS 之 ESM 消費端可 named import;IIFE 串接端
sed 剝最後一行即可。
124 lines
7.3 KiB
HTML
124 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-Hant">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>cjk-autospace — Changelog</title>
|
||
<meta name="generated-at" content="2026-05-22">
|
||
<meta name="source" content="cjk-autospace · docs branch">
|
||
<!-- RUNTIME_CSS -->
|
||
</head>
|
||
<body>
|
||
|
||
<header class="page">
|
||
<div class="meta">
|
||
<h1>cjk-autospace — Changelog</h1>
|
||
<p class="subtitle">時間倒序。架構細節見同分支 <code>index.html</code>。</p>
|
||
<p class="timestamp"><time>2026-05-22</time> · <span>docs branch</span></p>
|
||
</div>
|
||
<div class="actions">
|
||
<!-- ACTIONS -->
|
||
</div>
|
||
</header>
|
||
|
||
<main>
|
||
|
||
<h2>2026-05-26 — 補 ESM <code>export</code>(四種消費形式並存)</h2>
|
||
|
||
<p>下游 Vite / Rollup / TypeScript 之靜態 ESM 解析需要真正之 <code>export</code> 關鍵字;原 UMD-ish(<code>module.exports</code> + <code>globalThis</code>)對 ESM 消費端仍須走「副作用導入 + 從 global 取 factory」之 workaround。檔尾在既有 CJS / globalThis 兩塊後加 <code>export { createCjkAutospace }</code>,順序刻意如此 —— 讓 IIFE 串接端(Claude 模板 <code>build.sh</code> / Nvim peek build hook)只需以 <code>sed '/^export {/d'</code> 剝最後一行。</p>
|
||
|
||
<p>四種消費形式並存:ESM <code>import</code> / CommonJS <code>require</code> / browser <code>globalThis</code> / IIFE 串接(後者需剝 <code>export</code> 行)。</p>
|
||
|
||
<h2>2026-05-26 — Pass C:長英文段 lang 包裝(預設啟用)</h2>
|
||
|
||
<p>解決 CJK 兩端對齊正文中行末長英文詞之斷行問題。原模板於 runtime 端用 <code><wbr></code> 每 6 字元亂插斷詞機會,產生兩個觀感問題:(1)位置與音節邊界無關,斷在怪位;(2)<code><wbr></code> 為 zero-width,斷處不顯連字符,讀者無法辨認「上行末是被斷開的詞」。</p>
|
||
|
||
<p>Pass C 走另一條路:把 <code>[A-Za-z]{N,}</code>(預設 <code>N=6</code>)之長英文段包進 <code><span lang="en"></code>,配合消費端 CSS:</p>
|
||
|
||
<pre><code>[lang|="en"] {
|
||
hyphens: auto;
|
||
-webkit-hyphens: auto;
|
||
hyphenate-limit-chars: 6 3 3;
|
||
hyphenate-character: "-"; /* 強制 U+002D 而非預設 U+2010 */
|
||
-webkit-hyphenate-character: "-";
|
||
}</code></pre>
|
||
|
||
<ul>
|
||
<li>瀏覽器原生 <code>hyphens: auto</code> 用 en 字典做斷詞 + 渲染連字符;連字符純由 CSS 渲染,<strong>DOM 內不存在</strong> → 選取 / 複製返回原文無污染(符合「斷字符僅供渲染」之核心約束)</li>
|
||
<li>冪等:parent 為 <code><span lang></code> 直接跳過,重跑或 MutationObserver 觸發不會重複包裝</li>
|
||
<li>skip 鏈與 Pass A / B 共用 <code>isSkipped</code>:CODE / KBD / PRE / SAMP / TT / VAR / SCRIPT / STYLE / TEXTAREA / INPUT / SVG / contentEditable / <code>data-md-key</code> 皆跳過</li>
|
||
<li><strong>預設啟用</strong>。<code>longWordWrap: false</code> 顯式關閉;<code>{ minLength, lang }</code> 自訂粒度與標語</li>
|
||
</ul>
|
||
|
||
<h3>字型陷阱:U+2010 之全形 CJK 設計</h3>
|
||
|
||
<p>瀏覽器 <code>hyphens: auto</code> 預設在斷處插 U+2010 HYPHEN。Noto Serif CJK SC 等 CJK serif 字型把 U+2010 設計為 <strong>全形 1 em</strong>(與一個漢字同寬),以服務 CJK 範圍表達(<code>1月—3月</code>);而 U+002D HYPHEN-MINUS 在同字型內為窄拉丁(約 0.35 em)。直接吃預設會看到「全形連字符」突兀地接在英文詞末。</p>
|
||
|
||
<p>解法是消費端 CSS 加 <code>hyphenate-character: "-"</code>,強制使用 U+002D;仍為純視覺渲染,DOM 與剪貼簿不受影響。lib 不涉入字型決策,僅在文檔中提示。</p>
|
||
|
||
<h2>2026-05-22 — 初始發布</h2>
|
||
|
||
<ul>
|
||
<li>工廠函式 <code>createCjkAutospace(options)</code>,回傳 <code>{ apply(root?) }</code>。Port 自 Pangu.js v7.2.1 規則表(MIT 授權),覆寫架構為雙 pass:
|
||
<ul>
|
||
<li><strong>Pass A — per-block Pangu on tag-stripped text</strong>:對每個 BLOCK 走 DFS 收集邏輯文本(樣式標籤透明、PILL 與子 BLOCK 中斷 run),整段套 <code>panguSpace</code>,把 MARK 反映射回 textNode/offset 並插入 <code>.cjk-autospace</code> marker span。</li>
|
||
<li><strong>Pass B — pill boundary, style-inline aware</strong>:對每個 PILL 透過樣式鏈遞迴找邏輯鄰字(<code>adjacentLogicalChar</code>),按 0/1/多+特殊規則處理空白。</li>
|
||
</ul>
|
||
</li>
|
||
<li>標籤三分類:STYLE_INLINES / PILL / BLOCK,皆可由消費端配置。</li>
|
||
<li>UMD-ish export:同時支援 ESM <code>import</code>、CommonJS <code>require</code>、browser global <code>globalThis.createCjkAutospace</code> 與 inline <code><script></code> 函式宣告形式。</li>
|
||
<li>TS 宣告:<code>cjk-autospace.d.ts</code> 提供完整 <code>CjkAutospaceOptions</code> 與 <code>CjkAutospaceInstance</code> 型別。</li>
|
||
<li>初始消費者:
|
||
<ul>
|
||
<li>Claude HTML 模板(<code>Base/templates/html/runtime/lib/cjk-autospace/</code>,pillSelector <code>"code, kbd"</code>)</li>
|
||
<li>Peek.nvim Markdown 預覽 shim(<code>Nvim/lua/user/lib/cjk-autospace/</code>,pillSelector <code>"code, kbd, mark, samp"</code>)</li>
|
||
<li>cdrop(<code>cdrop/web/src/lib/cjk-autospace/</code>,pillSelector <code>"code, kbd, .cjk-pill"</code>)</li>
|
||
</ul>
|
||
</li>
|
||
<li>docs 分支:<code>index.html</code>(架構詳細文檔)+ <code>CHANGELOG.html</code>(本檔)。</li>
|
||
</ul>
|
||
|
||
<div class="callout info">
|
||
<span class="label">設計來源</span> 雙 pass 架構是原創設計,解決 Pangu.js 原版「text-node walker 看不到跨元素邊界」之問題(典型癥狀:<code><strong>是</strong> Neovim</code> 此類邊界無法被識別)。
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<footer class="page">
|
||
<p>cjk-autospace · docs branch · CHANGELOG</p>
|
||
</footer>
|
||
|
||
<!-- RUNTIME_SPRITE -->
|
||
|
||
<script type="text/markdown" id="md-source">
|
||
# cjk-autospace — Changelog
|
||
|
||
## 2026-05-26 — 補 ESM `export`(四種消費形式並存)
|
||
|
||
- 檔尾加 `export { createCjkAutospace }`,順序在 CJS / globalThis 兩塊之後 → IIFE 串接端只需 `sed '/^export {/d'` 剝最後一行
|
||
- 四種消費形式並存:ESM `import` / CommonJS `require` / browser `globalThis` / IIFE 串接
|
||
|
||
## 2026-05-26 — Pass C:長英文段 lang 包裝(預設啟用)
|
||
|
||
- 把 [A-Za-z]{N,} 之長英文段包進 `<span lang="en">`,配消費端 CSS `[lang|="en"] { hyphens: auto; ... }` 用瀏覽器原生 en 字典斷詞 + 渲染連字符
|
||
- 連字符純由 CSS 渲染,**DOM 內不存在**,選取 / 複製返回原文無污染
|
||
- 預設啟用;`longWordWrap: false` 顯式關閉
|
||
- 字型陷阱:CJK serif 字型把 U+2010 設計為全形(1 em),須加 `hyphenate-character: "-"` 強制 U+002D 才不會看到全形連字符
|
||
|
||
## 2026-05-22 — 初始發布
|
||
|
||
- 工廠函式 createCjkAutospace(options)。Port 自 Pangu.js v7.2.1 規則表。
|
||
- 雙 pass 架構:
|
||
- Pass A — per-block Pangu on tag-stripped text
|
||
- Pass B — pill boundary, style-inline aware
|
||
- 標籤三分類:STYLE_INLINES / PILL / BLOCK,皆可配置。
|
||
- UMD-ish export + TS 宣告。
|
||
- 初始消費者:Claude HTML 模板、Peek.nvim、cdrop。
|
||
- docs 分支:index.html(架構)+ CHANGELOG.html(本檔)。
|
||
</script>
|
||
|
||
<!-- RUNTIME_JS -->
|
||
|
||
</body>
|
||
</html>
|