From a00b35577e36b79971b0734d74f4db16ec54fdb5 Mon Sep 17 00:00:00 2001 From: commilitia Date: Tue, 9 Jun 2026 16:03:06 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E6=A8=99=E9=BB=9E=E6=87=B8?= =?UTF-8?q?=E6=8E=9B=20=EF=BC=8B=20=E5=9E=82=E6=87=B8=E5=AD=97=E9=81=BF?= =?UTF-8?q?=E5=85=8D=20=EF=BC=8B=20=E8=A1=8C=E7=AB=AF=E7=A6=81=E5=89=87=20?= =?UTF-8?q?=E6=95=B4=E9=AB=94=E5=AF=A6=E4=BD=9C=E8=A8=88=E5=8A=83=EF=BC=88?= =?UTF-8?q?ARCHITECTURE=20=C2=A76.5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 將三個相關機制(皆處理行端/段末之標點與字)整合為一份待實作蓝图,並補入前置「功能分級」。 - 6.5.0a 功能分級(前置):把功能分文本級(spacing、jiya baseline/連續挤压——對單行/單元素 即有意義)與段落級(jinze 避頭尾、行端半形/懸掛、gapTrim、orphan 垂懸字、longWord——僅多行 塊有意義)。下游經 data-jz-level="text" / 選項 level.text 標記元素(標題/按鈕只文本級、不要 懸掛/避孤字)。pass 標 level、finder.levelFor、段落級 pass gate 跳過 text-level。 - 6.5.0 四機制分工與邊界:禁則=斷行層趕標點到邊;行端半形/懸掛=渲染層紧排/凸出(互斥模式 lineEnd squeeze|hang);垂懸字=斷行層保末行實義字≥N。正交可疊加。垂懸字 vs 懸掛唯一重疊 「純標點末行」現由方案 C 副作用消除,未來可條件化交懸掛吸回。 - 6.5.1 垂懸字(方案 C):nowrap 綁定段末 N 實義字、數學保證末行≥N、免測 layout、符號不計、 單行段無效、可配 orphanChars;order 70。先做。 - 6.5.2 懸掛:自管負 margin(不用 CSS hanging-punctuation);複用 lineedge layout;行末點號/ 閉類右凸、行首開類左凸;併入行端模式;lang 閘(繁體預設不懸掛);風險=凸出量校準、自我應驗。 - 6.5.3 禁則 review、6.5.4 pass order、6.5.5 分步順序(0 分級→1 垂懸字→2 lineedge 重構→ 3 懸掛→4 邊界→5 文檔)、6.5.6 未決(預設值、凸出量、嵌套邊界字定位)。 僅文檔(無代碼改動)。 --- ARCHITECTURE.md | 133 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 7 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b7beab7..0046002 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -480,14 +480,133 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j 攀爬找流內鄰字(已於 `edgeRect` 處理 jz-* 包裹之攀出);屬 layout 層,jsdom 無法 驗,須瀏覽器目視。 -### 6.5 標點懸掛(Hanging)— 後續 +### 6.5 標點懸掛 + 垂懸字避免 + 行端禁則 — 整體計劃(待實作) -- **Han**:行尾標點懸掛出版心,需量測。 -- **我們**:layout pass——量測各行末,對行末可懸掛標點施負位移;掛 - `ResizeObserver` 重算。`order=90`(最後)。lang 閘:**繁體橫排預設不懸掛** - (clreq;`zh-Hant` 預設關),可開。 -- **預留**:依賴 `jz-char`/`jz-cs` 既有結構 + 一個 layout 後鉤子;切片 1 的 - charify 已備妥對象,加入時不動既有 pass。 +三個相關機制之**整體實作計劃**(同步引入),皆處理「行端/段末之標點與字」;其分層職責須先 +釐清,以免重複處理或衝突。**前置**須先落地「功能分級」(見 6.5.0a),因懸掛/垂懸字屬段落級、 +不應作用於標題/按鈕/單行文本。 + +#### 6.5.0a 功能分級:文本級 vs 段落級 + 元素標記(前置基礎設施) + +**動機**:懸掛/垂懸字/禁則等為**段落級**功能(依賴行/段布局),不應作用於標題、按鈕、單行 +或單元素文本;而中西間隙、標點挤压為**文本級**,任意文本片段皆適用且想要。下游須能**方便標記** +元素屬哪級。此為貫穿性基礎設施,實作時應提升為正式架構節(§3.x);此處先記計劃。 + +**分類(含現有與待加功能)**: + +| 級別 | 功能 | 判據/依賴 | +|---|---|---| +| **文本級** | `spacing`(中西間隙)、`jiya` baseline 政策半形、`jiya` 連續挤压(adjacency) | 僅字符鄰接,對單行/單元素文本即有意義 | +| **段落級** | `jinze` 避頭尾、行端(半形/懸掛)、`gapTrim`、`orphan` 垂懸字、`longWord` 斷詞 | 需行/段布局(換行、行端、段末、justify)才有意義 | +| 貫穿 | `charClass`、原子透明、normalize | 基礎設施,不分級 | + +直覺:文本級=「字符級排版」(間隙、標點形態);段落級=「行/段級排版」(換行、行端、段末)。 + +**標記 API(下游)**: +- 預設推斷:塊級元素(`blockTags`:p/div/li/td…)→ **段落級(全功能)**。 +- 顯式降級:`data-jz-level="text"` 於元素/祖先 → 該子樹**僅文本級**(段落級功能自動關); + `data-jz-level="paragraph"`(或不標)→ 全功能。 +- 選項 `level?: { text?: string }`:選擇器一鍵標記(如 `level:{ text: "h1,h2,h3,button,.ui" }`)。 +- 典型:標題/按鈕/UI 文字標 **text-level**(要間隙與標點半形、不要懸掛/避孤字/避頭尾); + 正文 `

` 預設全功能。 + +**實現**: +- 每個 pass 加元數據 `level: "text" | "paragraph"`。 +- `finder.levelFor(el)`:查 `data-jz-level` 祖先 + 選項 `level.text` 選擇器 + 預設(塊→段落)。 +- gate:段落級 pass 對 text-level 元素跳過;文本級 pass 不受限。與現有 `blocks`/ + `featureEnabledFor` 疊加(level=粗粒度語義組先判,blocks=細粒度逐功能後調)。 +- **文本級功能須支持非塊/單元素**:`spacing` 現用 `eachBlock`,須確認 scope root 為 inline/ + 單元素時亦能處理(或放寬走訪),使單行標題等之中西間隙、標點半形生效。 + +**與本批關係**:先落地分級(pass 標 level、`levelFor`、`data-jz-level`/選項)→ orphan/hanging +註冊為段落級,自動只作用段落級元素、跳過 text-level 者。實作順序插於 6.5.5 之首。 + +#### 6.5.0 四機制之分工與邊界(核心約定,實作前必讀) + +| 機制 | 作用層 | 唯一職責 | 手段 | 狀態 | +|---|---|---|---|---| +| 禁則(§6.4 jinze) | **斷行層** | 把標點趕到正確的邊(點號/閉類→行末、開類→行首;連續標點不拆) | nowrap `jz-jinze` | 已實作 | +| 行端半形(lineedge 現有) | **渲染層·紧排** | 行首開類/行末閉類**收半形** | `jz-half-le`(halt) | 已實作(將併入行端模式) | +| 標點懸掛(本計劃) | **渲染層·凸出** | 行末點號/閉類**右凸**、行首開類**左凸**出版心 | 負 `margin` | 待實作 | +| 垂懸字避免(本計劃) | **斷行層** | 段末行 **CJK 實義字數 ≥ N** | nowrap `jz-orphan` | 待實作 | + +- **正交性**:斷行層(禁則/垂懸字,管「哪些字符在哪行、不可斷」)與渲染層(半形/懸掛,管 + 「邊緣標點凸出/收縮」)作用於不同 CSS 維度(`white-space` vs `margin`),可疊加共存。 +- **協同**:禁則決定標點落行首或行末 → 半形/懸掛對落在邊緣者施收縮/凸出。 +- **行端「半形 vs 懸掛」互斥**(同屬渲染層):將 lineedge 行端處理升級為可配模式 + `lineEnd: "squeeze"(現有半形)|"hang"(懸掛)|"none"`,二者共用行端標點偵測碼。 +- **垂懸字 vs 懸掛邊界**(已研究):垂懸字限「末行實義字 ≥ N」、懸掛限「邊緣標點凸出」。唯一 + 重疊=**純標點末行**(實義字=0):懸掛可「吸回」(不動正文)、垂懸字綁定可「拉字下來」。 + 約定:方案 C(無測量)**附帶**消除純標點末行(副作用,現有益無害);未來若改由懸掛吸回 + (更優),把 C 綁定**條件化**(僅末行實義字 ∈ [1,N−1] 才綁),借懸掛 layout pass 之測量協同 + 判定,C 不獨立測。末行實義字 ∈ [1,N−1] 僅垂懸字(換行)可解(懸掛不增實義字)。 + +#### 6.5.1 垂懸字避免(方案 C,斷行層,無測量)— 先做 + +- **目標**:段末行 CJK 實義字數 ≥ N(預設 2;標點/符號不計)。單行段無效。 +- **機制**:standalone pass,遍歷作用域段落;自段末向前數 N 個 CJK 實義字(`ruleset.cjk` 判定、 + 跳過標點/空白/西文計數),把「第 N 個實義字起至段末」(含其間/尾隨標點)包入 `` + (CSS `white-space: nowrap`)。 +- **保證(數學、免測 layout)**:該整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型/ + 瀏覽器成立。平時無害(末行本多字時不改變),僅末行將塌為 `;行首開類加 + `jz-hang-l`→`margin-left: -<凸出量>`。 +- **與現有行端半形整合**:抽出「行端標點偵測」共用,按 `lineEnd` 模式加 `jz-half-le`(squeeze) + 或 `jz-hang-*`(hang)。重構後 squeeze 行為須不變(回歸測試保綠)。 +- **凸出量**:取決於標點 advance(halt 半形 0.5em/全形 1em/margin 盒 0.5em)——**需 headless + 實測校準**(風險)。目標令標點墨色邊緣齊版心。 +- **lang 閘**:clreq——繁體橫排預設不懸掛(`zh-Hant` 預設 squeeze/none);簡體可開。經 + `options.hanging` + 逐 lang。預設**待定**(建議預設關,顯式開)。 +- **自我應驗**:懸掛凸出改行寬→改斷行→行末標點變→自我應驗(同 gapTrim/lineedge)。緩解: + 仿 gapTrim「起始全施/穩定迭代」教訓。**重點風險**。 +- **order**:layout pass,最後(整合進 lineedge 行端模式,或 order≈94)。 +- **CSS**:`jz-char.jz-hang-r{margin-right:-…}` `.jz-hang-l{margin-left:-…}`。`revert` 清 class。 +- **跨瀏覽器**:負 margin 一致;須 Chrome/Safari/FF 目視(R1/R2)。headless 量測行末標點是否 + 凸出右緣。 + +#### 6.5.3 行端禁則(§6.4)review + +- 現狀避頭尾已與懸掛協同(禁則趕標點到邊、懸掛凸出邊緣)。review:①連續標點群組 `jz-jinze` + 在行端懸掛時凸出最外側;②jz-orphan 與 jz-jinze 嵌套;③lineedge 偵測已跨 jz-jinze 攀爬。 + 預期 jinze 本身不需大改。 + +#### 6.5.4 統一 pass order(增補後) + +`20 charify → 25 jiyaAdj → 40 jinze → 50 spacing → 60 longWord → 70 orphan(垂懸字)→ +90 lineEdge(行端 squeeze/hang)→ 92 gapTrim`。 + +#### 6.5.5 實作順序(分步,風險遞增) + +0. **功能分級(前置,6.5.0a)**:pass 標 `level`、`finder.levelFor`、`data-jz-level`/選項 + `level.text`;段落級 pass gate 跳過 text-level 元素。orphan/hanging 依此確定適用範圍。 +1. **垂懸字(方案 C)**:純結構、無 layout、最獨立、風險最低 → 先做。 +2. **lineedge 重構為行端模式**:抽出偵測,現有半形=`squeeze`(行為不變、回歸保綠)。 +3. **懸掛 hang 模式**:加 `jz-hang-*` + 負 margin + 凸出量校準 + 自我應驗處理 + lang 閘。 +4. **邊界落地**:純標點末行本期 C 全包;記錄未來條件化路徑。 +5. **文檔/docs/demo**(resize-check 增懸掛、垂懸字檢查)。 + +#### 6.5.6 未決(實作時定) + +- 垂懸字預設開關(建議開 chars=2);懸掛 lang 預設(建議關)。 +- 懸掛凸出量(headless 校準);懸掛自我應驗策略。 +- jz-orphan 與 jz-jinze 嵌套之邊界字定位。 ### 6.6 標點修正(Biaodian normalize)— 後續(opt-in)