feat: 聚珍切片 1 — 中西間隙/標點擠壓/禁則 + v1 相容層
從零重寫之第一垂直切片(依 ARCHITECTURE.md 契約),涵蓋並超越 v1 全部功能。 核心基座(src/core):unicode 字元表+標點子類+字形側位;locale 語言與 全角/開明政策(全域 lang.style +逐 lang policy);dom(jz-* 工廠+可還原 標記);finder 遍歷引擎(avoid/scope.include/邏輯 run/pill 鄰字/分塊閘); pass 聚合管線。 功能 pass(src/typeset): - spacing:中西間隙採 margin 模型——包裹邊界左側字、以 margin-right 留隙, 不注入空白字元(textContent 完全不變、複製緊湊、justify 不暴增、不撐框、 行首乾淨)。含跨樣式邊界、pill、原檔空格移除。 - gapTrim(lineedge):layout pass,行末去隙,修正 justify 右緣內縮。 - longword:長英文詞 <span lang> + hyphens。 - jiya:標點 charify + 全角/開明/半角(全域 + 逐 lang);半形以字型 OpenType halt 渲染(按字形正確定位、不重疊,居中字形 !? 與繁體 locl 句逗點號皆正確); 行內連續擠壓。 - jinze:行首行末避頭尾(閉類/點號綁前字、開類綁後字,以詞元為邊界、長引文 中段可斷);亦為 justify 綁定載體。 - lineedge:行端擠壓 layout pass(括號引號;ResizeObserver 重算,瀏覽器專用)。 §8 justify:jz-char inline-block 原子,句末標點單份間距。 v1 相容層(compat/v1):createCjkAutospace().apply 映射,IIFE 全域別名。 構建:esbuild → ESM/IIFE/CSS;tsc → d.ts。測試:39 個 jsdom 案例。 demo:簡繁並列+justify+強制繁體開明+標點寬度量測,載 Noto webfont 作參考 (擠壓依賴字型 halt)。間隔號 · 不觸發中西間隙;200% 等詞元不被禁則切斷。
This commit is contained in:
+57
-27
@@ -76,8 +76,9 @@ jz.revert(root?); // 還原
|
||||
|
||||
```
|
||||
{
|
||||
// 全域
|
||||
lang: { default: "zh-Hant", policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" } },
|
||||
// 全域。style = 全域擠壓預設(quanjiao|kaiming|banjiao);policy = 逐 lang
|
||||
// 覆寫。優先序:policy[lang] > style > 內建預設(繁→全角、簡→開明)。
|
||||
lang: { default: "zh-Hant", style: "kaiming", policy: { "zh-Hant": "quanjiao" } },
|
||||
classPrefix: "jz",
|
||||
|
||||
// 作用域限定(§3.6)
|
||||
@@ -313,13 +314,28 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
|
||||
|
||||
- **Han**:插入 `<h-hws hidden>`,內含**真實空格** + `::before{content:' '}`,
|
||||
**未加 `user-select:none`** → 選取/複製會帶上空格(其已知缺陷)。
|
||||
- **我們**:finder 邊界感知地在 CJK↔西文邊界插入 `jz-hws`;間隙寬度由 CSS
|
||||
(`::before` 或內含空白 + 負微調)給定,元素 `user-select:none`(I1,**修正
|
||||
Han 的選中缺陷**)。WHERE 之規則沿用 v1 pangu 規則表(已驗證)。
|
||||
- **跨瀏覽器**:`user-select`/inline 普遍支援。
|
||||
- **lang**:間隙量可依 `:lang` 微調(如日文與中文略異),預設一致。
|
||||
- **調整**:copy-clean(I1)+ justify 安全(I5/§8)。涵蓋 v1 Pass A、Pass B
|
||||
(pill `code/kbd` 邊界亦走同一機制,pill 由 avoid 與鄰接判定處理)。
|
||||
- **我們(margin 模型)**:finder 邊界感知地把邊界**左側之一個字**(CJK 或西文)
|
||||
包進 `jz-hws`,間隙由 CSS `margin-right`(0.25em)提供——**不注入任何空白字元**。
|
||||
WHERE 之規則沿用 v1 pangu 規則表(已驗證);作者原寫之 CJK↔西文空格一律移除
|
||||
(改由 margin 留隙)。
|
||||
- **為何不用空白字元/inline-block(justify 三難)**:純 CSS 下,CJK↔西文間隙在
|
||||
`justify` 必有一個邊緣瑕疵——①真實空白→被當詞間空白**暴增**;②inline-block 固定
|
||||
寬→罕見落**行首縮排**;③`margin-right`→**行末右緣內縮 0.25em**。選 ③(margin),
|
||||
因其行首乾淨、不撐框、不暴增、`textContent` 完全不變(純 copy-clean,複製緊湊),
|
||||
並以 §6.1a 之 layout pass 消除行末內縮。
|
||||
- **跨瀏覽器**:`margin`/inline 普遍支援。
|
||||
- **copy-clean(I1,較 Han 更純)**:間隙為純視覺 margin,`textContent` 不增不減
|
||||
語義字元,剪貼板得緊湊原文。
|
||||
- **切片**:涵蓋 v1 Pass A、Pass B(pill `code/kbd` 邊界亦走同一機制——左字或
|
||||
pill 元素包入 `jz-hws`;pill 由 avoid 與鄰接判定處理)。
|
||||
|
||||
### 6.1a 行末去隙(gapTrim,justify 修正)— 切片 1
|
||||
|
||||
- **問題**:margin-right 落在行末時,justify 下使右緣內縮 0.25em。
|
||||
- **我們**:layout pass `gapTrim` 量測各 `jz-hws`,對「其字落於行末(後一內容在
|
||||
更低行)」者加 `jz-hws-trim`(CSS `margin-right:0`),該行遂齊右、無內縮。掛
|
||||
`ResizeObserver`+字型載入後重算。純版面、瀏覽器專用(jsdom 跳過)。與 `lineedge`
|
||||
共用量測工具與 layout 安裝器。
|
||||
|
||||
### 6.2 長英文詞斷詞包裝 — 切片 1
|
||||
|
||||
@@ -334,25 +350,36 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
|
||||
- **Han**:charify 標點為 `<h-char class="bd-jiya …"><h-inner>`,以負
|
||||
`letter-spacing`/`margin` 擠壓;連續、行端、簡繁差異以 CSS + `:lang()` 落實
|
||||
(`bd-cop:lang(zh-Hant)` → 不擠=全角式)。
|
||||
- **我們**:同構——charify → `jz-char.bd-jiya` + `jz-inner`;擠壓量寫在
|
||||
`juzhen.css`,依 `bd-*` class 與 `:lang()` 套用。**全角式**(zh-Hant:`bd-cop`
|
||||
不擠)/**開明式**(zh-Hans:`bd-cop` 擠半形),政策由 `locale.style` 與
|
||||
`:lang()` 一致驅動(I3)。
|
||||
- **跨瀏覽器(I4)**:用負 `margin`/`letter-spacing`,**不依賴** `halt`/
|
||||
`text-spacing-trim`,故 Chrome/Safari/FF 一致。(註:v1 Pass D 用 `halt`,
|
||||
跨瀏覽器不一致;此處即為改進。)
|
||||
- **調整**:行端擠壓以 `jz-cs` 補償空白於行邊界折疊之機制達成(CSS 主導,免
|
||||
逐行量測);justify 安全見 §8。
|
||||
- **切片**:涵蓋並超越 v1 Pass D(開明式),且加入全角式與 lang 切換。
|
||||
- **我們**:同構——charify → `jz-char.bd-*` + `jz-inner`;半形與否寫在
|
||||
`juzhen.css`,由 JS 解析 `locale.style`(讀 lang)後加 `jz-half`/`jz-half-le`
|
||||
class 觸發(I3;改用 class 而非 CSS `:lang()`,以避免 `:lang(zh-Hans)` 不匹配
|
||||
`zh-CN` 等地區標籤之陷阱)。三機制並集落地:①**baseline 政策**(全角不擠/
|
||||
開明擠句內點號+括號引號/半角全擠);②**行內連續擠壓**(`jiyaAdjacencyPass`,
|
||||
相鄰標點對向側收一字,lang 無關);③**行端擠壓**(`lineedge.ts` layout pass)。
|
||||
- **跨瀏覽器(I4)— 修訂**:半形改以字型 OpenType **`halt`**(`font-feature-
|
||||
settings:"halt"`)渲染,**非**負 `margin`。原因:負 margin 假設可壓縮空白全在
|
||||
單側,對**居中字形**(`!?`、繁體 `locl` 下之 `。,`)會把字面拉入鄰字而**重疊**;
|
||||
`halt` 收的是字身寬度、由字型按字形正確定位(簡左/繁中/括號偏側皆對),故
|
||||
不重疊。`font-feature-settings:"halt"` 各引擎一致(當初疑慮之不一致者為**自動**
|
||||
的 `text-spacing-trim`/`chws`,非顯式 `halt`);缺 `halt` 之字型優雅降級為全形。
|
||||
鄰接/行端之「收哪一字」之**決策**仍由 `blankSides` 邏輯定,渲染統一為 `halt`。
|
||||
- **切片**:涵蓋並超越 v1 Pass D(開明式),加入全角式、lang 切換、行內連續與
|
||||
行端擠壓。
|
||||
|
||||
### 6.4 禁則(Jinze,避頭尾)+ justify 綁定 — 切片 1(基礎)/後續(完整)
|
||||
|
||||
- **Han**:`h-jinze` 綁定行首行尾不可出現之標點與鄰字,避免標點落行首/行尾。
|
||||
- **我們**:`jz-jinze` 綁定為不可斷單元(CSS `display:inline-block` 或等價,內部
|
||||
不開 justify gap)。**此亦為 §8 justify 單份間距之載體**:句末標點與其字面留白
|
||||
成一原子單元,justify 伸縮只落單元之間。
|
||||
- **切片**:切片 1 先做「足以保證 §8 與標點不破壞間距」之最小綁定;完整避頭尾
|
||||
(所有禁則對象、行首縮排聯動)列後續,但用同一 `jz-jinze` 結構,無返工。
|
||||
- **我們**:`jz-jinze`(CSS `display:inline-block; white-space:nowrap`)綁定不可斷
|
||||
單元。**避頭尾已實作**(`jinze.ts`):因 jiya 把標點原子化為 inline-block,原子
|
||||
邊界成可斷點、破壞瀏覽器原生 UAX#14 避頭尾,故補回——把「不可置行首」之標點
|
||||
(閉類/點號/間隔/連接省略)綁到**前一字**、「不可置行末」之開類綁到**後一字**,
|
||||
且**只隔離單一邊界字**(長引文中段仍正常斷行,不溢出)。實作為兩階段:依原始
|
||||
相鄰算禁斷邊界→切邊界字;重掃併入 nowrap 群組。亦為 §8 justify 綁定載體。
|
||||
- **切片**:切片 1 完成行首行末避頭尾(閉類/點號避頭、開類避尾);行首縮排聯動、
|
||||
更細之禁則對象列後續,沿用同一 `jz-jinze` 結構。
|
||||
- **已知交互(待瀏覽器精修)**:`lineedge` 之行端偵測需跨 `jz-jinze` 群組邊界向上
|
||||
攀爬找流內鄰字(已於 `edgeRect` 處理 jz-* 包裹之攀出);屬 layout 層,jsdom 無法
|
||||
驗,須瀏覽器目視。
|
||||
|
||||
### 6.5 標點懸掛(Hanging)— 後續
|
||||
|
||||
@@ -439,9 +466,12 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
|
||||
|
||||
## 9. 跨瀏覽器策略
|
||||
|
||||
- **一致性關鍵層**(間隙、擠壓、justify):只用 `margin`、`letter-spacing`、
|
||||
`inline-block`、`user-select`、`:lang()`、`:where()`、`hyphens`——三大引擎
|
||||
(Blink/WebKit/Gecko)皆穩定支援。
|
||||
- **一致性關鍵層**(間隙、擠壓、justify):只用 `margin`、`inline-block`、
|
||||
`user-select`、`white-space`、`:where()`、`hyphens`,及字型 OpenType
|
||||
`font-feature-settings:"halt"`(標點半形;各引擎一致,效果僅依字型是否含 halt,
|
||||
Noto CJK 具備,缺則優雅降級為全形)——三大引擎(Blink/WebKit/Gecko)皆穩定
|
||||
支援。**注意**:標點半形不用負 `margin`(對居中字形會重疊),改用 `halt`(見
|
||||
§6.3 修訂)。
|
||||
- **漸進增強(非必要)**:`text-spacing-trim`(Blink)、`hanging-punctuation`
|
||||
(WebKit)、`text-emphasis`、`text-autospace`——僅在支援時錦上添花,缺席不影響
|
||||
基本排版(I4)。
|
||||
|
||||
Reference in New Issue
Block a user