feat(rules): 建立共享排版契约并收束 WebKit 与 Unicode 基线
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
npm install
|
||||
npm run build # esbuild → dist/juzhen.{mjs,iife.js,css};tsc → dist/index.d.ts
|
||||
npm test # jsdom DOM 正確性測試
|
||||
node --test test/shared-rules.test.mjs # 共享規則 Schema/黃金向量/Web 漂移守門
|
||||
npm run test:wkwebview # macOS 原生 WKWebView 版面/observer E2E(需 Xcode 與 GUI 會話)
|
||||
```
|
||||
|
||||
產物(`dist/`,已入庫):
|
||||
@@ -29,6 +31,29 @@ npm test # jsdom DOM 正確性測試
|
||||
| `dist/juzhen.iife.js` | IIFE,全域 `Juzhen`,原生 `<script>` 直跑 |
|
||||
| `dist/juzhen.css` | 合併樣式(**必須引入**,視覺尺寸全在此) |
|
||||
| `dist/index.d.ts` | TypeScript 型別宣告 |
|
||||
| `rules/juzhen-rules.json` | 平台中立之共享排版規則(Web/XeLaTeX 共用) |
|
||||
| `rules/golden-vectors.json` | 跨實作語義黃金向量 |
|
||||
|
||||
---
|
||||
|
||||
## 共享規則契約
|
||||
|
||||
`rules/` 是 Web/CSS 與並行 XeLaTeX 實作之唯一規則權威源;初版規則版本為 `1.0.0`。
|
||||
規則以 Unicode code-point 區間、語言政策、標點寬度、間隙、禁斷與段末約束描述「應發生
|
||||
什麼」,不規定 DOM/CSS、TeX node/glue/penalty 或其他 adapter 的實作機制。
|
||||
|
||||
套件提供四個唯讀子路徑:
|
||||
|
||||
```js
|
||||
import rules from "cjk-autospace/rules" with { type: "json" };
|
||||
import schema from "cjk-autospace/rules/schema" with { type: "json" };
|
||||
import vectors from "cjk-autospace/rules/vectors" with { type: "json" };
|
||||
import vectorsSchema from "cjk-autospace/rules/vectors-schema" with { type: "json" };
|
||||
```
|
||||
|
||||
規則版本、Schema 版本、變更程序與 adapter 邊界詳見 [`rules/README.md`](./rules/README.md)。
|
||||
任何規則變更必須同步更新 canonical JSON、Schema、黃金向量,並讓 Web 與 XeLaTeX adapter
|
||||
同時通過相同語義向量;任一實作不得單邊分叉規則。
|
||||
|
||||
---
|
||||
|
||||
@@ -110,16 +135,17 @@ jz.observe(document.body); // 之後 DOM 變動即自動增量恢復
|
||||
|
||||
| 功能 | 說明 |
|
||||
|---|---|
|
||||
| **中西間隙** `spacing` | CJK↔西文邊界插入 copy-clean 之 `jz-hws`(`user-select:none`,剪貼板跳過)。「西文」涵蓋拉丁(含擴充 A/B,拼音聲調 `ā ǎ ē`)、希臘、西里爾、數字、貨幣(`€ ₩ ₿`)、數學運算符等;CJK 標點(`。,「」()……` 等)不誤判為西文、不生隙。含跨樣式行內邊界與 pill/隔離元素邊界(`code`/`kbd`/`.katex` 與 `mark`,兩端補隙口徑一致;pill 緊鄰標點時穿越 `jz-jinze` 仍補間隙;pill 跨行右隙、間隙落行末之自我應驗皆已修)。**pill 之邏輯鄰字為標點時(如 `漢字。<code>`)不誤加間隙**(標點非 pill 鄰字;`jz-char`/`jz-inner` 透明穿越,與 `collectRuns` 一致)。贅餘作者空格一律正規化:CJK↔西文吸收為受管間隙、CJK↔CJK(含跨 inline 標籤)剝除不留隙。 |
|
||||
| **中西間隙** `spacing` | CJK↔西文邊界以 copy-clean 之 `jz-hws` 與 `margin-right` 留隙;**不插入空白字元**,故剪貼板不多出空格。唯跨節點 IVS 產物以 `::after` 產生的 `U+200B` 斷行機會設 `user-select:none`;它不進入 DOM/`textContent`。「西文」涵蓋拉丁(含擴充 A/B,拼音聲調 `ā ǎ ē`)、希臘、西里爾、數字、貨幣(`€ ₩ ₿`)、數學運算符等;CJK 標點(`。,「」()……` 等)不誤判為西文、不生隙。含跨樣式行內邊界與 pill/隔離元素邊界(`code`/`kbd`/`.katex` 與 `mark`,兩端補隙口徑一致;pill 緊鄰標點時穿越 `jz-jinze` 仍補間隙;pill 跨行右隙、間隙落行末之自我應驗皆已修)。**pill 之邏輯鄰字為標點時(如 `漢字。<code>`)不誤加間隙**(標點非 pill 鄰字;`jz-char`/`jz-inner` 透明穿越,與 `collectRuns` 一致)。贅餘作者空格一律正規化:CJK↔西文吸收為受管間隙、CJK↔CJK(含跨 inline 標籤)剝除不留隙。 |
|
||||
| **長英文詞** `longWord` | `[A-Za-z]{6,}` 包入 `<span lang="en">`,配合 CSS `hyphens:auto` 原生斷詞(DOM 無連字符 → 複製不污染)。 |
|
||||
| **標點擠壓** `jiya` | 標點 charify 為 `jz-char`+`bd-*` class。三機制:①baseline 政策(全角式不擠/開明式擠句內點號+括號引號/半角式全擠);②行內連續擠壓(相鄰標點**雙側獨立**收——各標點若其有空白之側緊鄰另一標點即收半,故 `,「` 全角式與開明式皆 1em、`。」` 全角式 1.5em/開明式 1em;**唯句末點號接開類為句界**——`。「`/`?「` 保留句末點號右空白、僅收開類,全角式與開明式皆 1.5em;透明穿越 `strong`/`em` 等行內邊界);③行端擠壓(`lineedge` layout pass)。半形預設以字型 `halt` 渲染(按字形正確定位,居中字形如 `!?`/繁體 `。,` 不重疊;不依賴 `text-spacing-trim`)。**字型缺 `halt` 時可切 `margin` 後備模式**(見下節)。 |
|
||||
| **禁則** `jinze` | 行首行末避頭尾:閉類/點號綁前一字(不置行首)、開類綁後一字(不置行末),只隔離邊界字故長引文中段仍可斷。亦為 `justify` 綁定載體。邊界字落於**透明**行內樣式元素(`strong`/`em` 等)內時**克隆切分**只綁邊界詞元(避免整個元素入 `nowrap` 致行末整體掉行、上行留巨大空隙),切出之克隆標 `data-jz-kind="splitoff"`、`revert` 時自動併回原元素;不可切元素(`a`/`abbr`/`ruby`/帶 `id`,以及 **pill/隔離/avoid**——見「行內元素三分類」)退化為**整元素綁定**——pill(如行內公式 `.katex`)即作為原子鄰字單位整體綁入 `jz-jinze`,絕不下潛肢解其內部。 |
|
||||
| **垂懸字避免** `orphan` | 段末行 CJK 實義字 ≥ N(預設 2;標點/符號不計)。方案 C(斷行層、無測量):把段末「第 N 個實義字起至段末」包入 `jz-orphan`(`white-space:nowrap`),整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型成立。單行段無害。邊界字落於行內元素內時同樣**克隆切分**(只綁末 N 字、避免整個長元素入 `nowrap` 溢出容器;機制同禁則)。**預設開**(`orphan:false` 關,`{chars:n}` 調)。段落級功能。 |
|
||||
| ~~**標點懸掛** `hanging`~~ | **已移除**(§6.5.6):純負 margin 機制為機制級死路(寬度守恆矛盾,CSS 接觸不到斷行器),原生 `hanging-punctuation` 為唯一正解但僅 Safari 支援、且與本庫 inline-block 原子互斥。`hanging` 選項仍被接受(API 相容)但**無任何效果**;相關程式碼/CSS 已全數刪除,原生路徑屬遠期「原生管線」新功能。 |
|
||||
| **功能分級** `level` | 功能分文本級(中西間隙、標點擠壓——任意文本片段適用)與段落級(禁則、垂懸字、懸掛、長詞——需行/段布局)。塊級元素預設全功能;`data-jz-level="text"` 子樹或選項 `level:{text:"選擇器"}`(如標題/按鈕)僅跑文本級。 |
|
||||
| **功能分級** `level` | 功能分文本級(中西間隙、標點擠壓——任意文本片段適用)與段落級(禁則、垂懸字、長詞——需行/段布局)。塊級元素預設全功能;`data-jz-level="text"` 子樹或選項 `level:{text:"選擇器"}`(如標題/按鈕)僅跑文本級。 |
|
||||
| **justify 單份間距** | 每個 `jz-char` 為 `inline-block` 原子項,句末標點只貢獻一份對齊伸縮量。 |
|
||||
|
||||
後續(架構已預留,不返工):標點修正(簡↔繁)、著重號、注音/Ruby。
|
||||
相容選項 `hanging`/`biaodian`/`emphasis`/`ruby` 仍被接受,但當前均為
|
||||
**no-op**:沒有對應 pass、DOM 產物或 CSS。後三者僅屬明確標記的未來設計;
|
||||
`hanging` 之舊負 margin 實作已移除,僅保留 API 相容。
|
||||
|
||||
---
|
||||
|
||||
@@ -142,7 +168,6 @@ createJuzhen({
|
||||
jiya: true, // 或物件:{ halfWidth: "halt" | "margin", bias }
|
||||
jinze: true,
|
||||
orphan: true, // 垂懸字避免(預設開);或 { chars: 2 };false 關
|
||||
// hanging:已移除、無效果(見「標點懸掛」一節)
|
||||
level: { text: "h1,h2,h3,button,.ui" }, // 此選擇器子樹僅跑文本級功能(見下)
|
||||
pillSelector: "code, kbd, .katex", // 整體(pill)元素(見「行內元素三分類」)
|
||||
isolateSelector: "mark", // 內外隔離元素(預設 mark;"" 停用)
|
||||
@@ -214,8 +239,9 @@ createJuzhen({
|
||||
| `data-jz-skip` | (存在即可) | 標記元素為 avoid(內外皆不處理) |
|
||||
| `data-jz-halfwidth` | `halt|margin` | 逐子樹半形渲染模式 |
|
||||
|
||||
**預留、當前無效果**:`hanging`(已移除,見下);`biaodian`/`emphasis`/`ruby`(架構預留切片
|
||||
#7/#8)。注意頂層 `biaodian`(功能開關)與 `charClass.biaodian`(標點子類擴充表)**同名異義**。
|
||||
**相容 no-op 選項**:`hanging`/`biaodian`/`emphasis`/`ruby` 均可傳入,但當前不註冊
|
||||
pass,也不產生 DOM/CSS 效果。注意頂層 `biaodian` 與 `charClass.biaodian`(已實作的
|
||||
標點子類擴充表)**同名異義**。
|
||||
|
||||
### 逐元素標點樣式(`data-jz-style`/`stylePolicy`)
|
||||
|
||||
@@ -303,11 +329,11 @@ web component 等)採**嚴格白名單**、一律當**邊界**(語義同隔
|
||||
|
||||
- **文本級**(中西間隙 `spacing`、標點擠壓 `jiya`):僅依字符鄰接,**任意文本片段**(單行
|
||||
標題、按鈕、單一行內元素)皆適用且想要。
|
||||
- **段落級**(禁則 `jinze`、垂懸字 `orphan`、標點懸掛 `hanging`、長詞 `longWord`):依賴
|
||||
- **段落級**(禁則 `jinze`、垂懸字 `orphan`、長詞 `longWord`):依賴
|
||||
行/段布局(換行、行端、段末),對單行/非段落文本無意義甚至有害。
|
||||
|
||||
塊級元素(`p`/`div`/`li`/`h1`…)**預設段落級(全功能)**。把標題/按鈕/UI 文字標為
|
||||
**文本級**(要間隙與標點半形、不要懸掛/避孤字/避頭尾):
|
||||
**文本級**(要間隙與標點半形、不要避孤字/避頭尾):
|
||||
|
||||
```html
|
||||
<h1 data-jz-level="text">標題:只跑中西間隙與標點擠壓</h1>
|
||||
@@ -484,7 +510,8 @@ JS 只注入 `jz-*` 結構,**所有視覺尺寸在 `juzhen.css`**——故 CSS
|
||||
`jiya.bias` 逐字微調墨色偏側(見「字型適配工作流」)。
|
||||
7. **自動處理、無需消費端介入**:`juzhen.css` 已在 `.juzhen` 範圍內以 `@supports`
|
||||
關閉 Blink 原生 `text-spacing-trim`/`text-autospace`(避免與託管擠壓重複作用),
|
||||
並令注入間隙 `user-select: none`(複製乾淨)。
|
||||
間隙不注入空白字元;僅跨節點 IVS gap 之 `U+200B ::after`
|
||||
設 `user-select:none`,避免該斷行提示進入選取/複製。
|
||||
8. **段落屬性照常設、原子透明**:聚珍把標點拆成 inline-block 原子,但已確保這些原子對
|
||||
消費端段落樣式透明——可在段落正常設 `text-indent`(首行縮排)、`hanging-punctuation`、
|
||||
`text-decoration`(下劃線)等;庫內已歸零會被原子重複套用之繼承屬性、並令原子承接段落
|
||||
@@ -528,7 +555,7 @@ createJuzhen({
|
||||
cjk: "〇", // 追加為中文(CJK):與西文邊界補中西間隙、禁則/justify 視為單字
|
||||
western: "★☆", // 追加為西文(半寬標點亦歸此):與 CJK 邊界補間隙
|
||||
biaodian: { // 追加為全寬標點,按子類(jiya charify/擠壓、禁則避頭尾)
|
||||
stop: ".", // 句末(。!?類)
|
||||
stop: "‼", // 追加為句末點號(。.!?已內置)
|
||||
pause: "", // 句內(,、;:類)
|
||||
open: "", close: "", // 開/閉括號引號
|
||||
middle: "", liga: "", // 間隔號/省略破折
|
||||
@@ -537,10 +564,9 @@ createJuzhen({
|
||||
});
|
||||
```
|
||||
|
||||
**典型用例**:英文全角句號 `.`(U+FF0E,有別於中文句號 `。` U+3002)預設**未分類**
|
||||
——不被 charify、不挤壓、與 CJK 間不補隙。若內容用 `.` 作句末標點,以
|
||||
`charClass: { biaodian: { stop: "." } }` 歸為全寬句末標點,即比照 `。` 處理(開明式挤半形、
|
||||
全角式佔全形、行首避頭尾)。
|
||||
`.`(U+FF0E,全角句點)已是內置 `BD_STOP` 成員,無需再經
|
||||
`charClass` 追加;其政策與 `。!?` 一致。`charClass.biaodian` 用於追加尚未內置的
|
||||
符號(如上例 `‼`),不用來重複宣告內置字符。
|
||||
|
||||
要點:
|
||||
|
||||
@@ -566,6 +592,8 @@ v1 相容層(`createCjkAutospace` 導出、IIFE 之 `globalThis.createCjkAutos
|
||||
## 目視驗證
|
||||
|
||||
`demo/index.html` 載入 `dist/` 產物,簡繁並列、可切 `justify`、附 copy-clean 測試區。
|
||||
`demo/e2e.html` 是可機讀的核心版面與 MutationObserver 驗收頁;macOS 上可以
|
||||
`npm run test:wkwebview` 將同一頁面載入原生 `WKWebView`,自動執行全部斷言。
|
||||
`demo/fallback.html` 以**方正書宋 GBK**(無 `halt`)對照 `halt` 模式失效 vs `margin`
|
||||
後備生效。`demo/resize-check.html` 為**可拖曳容器**檢查頁:拖動方框寬度,驗證中西間隙在
|
||||
各寬度下恆穩(含行末去隙之自我應驗、pill 跨行右隙、貨幣/拼音/西里爾外文補隙、全角省略號
|
||||
|
||||
Reference in New Issue
Block a user