docs: 同步現行契約並保留逐字半形後備
This commit is contained in:
+84
-53
@@ -51,8 +51,9 @@ CSS box、observer、瀏覽器量測,以及 TeX node/glue/penalty/macro
|
||||
屬性);**所有視覺尺寸(margin/letter-spacing/寬度/懸掛位移)一律寫在
|
||||
`juzhen.css`**。同一段 DOM 在 justify 與否、主題與否下都成立。此分離是擴充性
|
||||
與跨瀏覽器調校的關鍵。
|
||||
- **I3 依 `lang` 行為**:每個 pass 解析節點的有效 `lang`(最近祖先),行為與
|
||||
CSS 皆以 `:lang()` 與 locale 政策驅動。全角式/開明式之別即由此決定。
|
||||
- **I3 依 `lang` 行為**:JS 解析節點的有效 `lang` 與逐元素樣式政策,決定標點是否半形,
|
||||
再以 `jz-half`/`jz-half-le` class 交由 CSS 渲染;CSS 不以 `:lang()` 另判寬度政策。
|
||||
字型地域字形由呼叫端的 `lang` 與字型決定,`options.lang.default` 不會改寫 DOM 的 `lang`。
|
||||
- **I4 跨瀏覽器一致**:間隙、擠壓等一致性關鍵層只用 `margin`/`letter-spacing`/
|
||||
`inline-block`/`user-select` 等普遍原語。`text-spacing-trim`/
|
||||
`hanging-punctuation`/`text-emphasis` 等僅作漸進增強,絕不作為唯一機制。**且當
|
||||
@@ -61,12 +62,12 @@ CSS box、observer、瀏覽器量測,以及 TeX node/glue/penalty/macro
|
||||
`text-spacing-trim` 不設定),使三引擎行為收斂於同一路徑(見 §9.1)。
|
||||
- **I5 justify 單份間距**:間隙與擠壓的結構設計,須保證每個標點在
|
||||
`text-align: justify` 下只貢獻**一份**對齊伸縮量(見 §8)。
|
||||
- **I6 冪等與可還原**:每個 pass 對其產物打標記,重跑跳過;提供 `revert` **乾淨移除聚珍注入之
|
||||
全部結構**(`jz-*` 元素、class、`data-jz-*` 屬性;wrap→解包還原原內容、marker→移除、
|
||||
splitoff→併回原元素),DOM 回到 pass 前狀態之**邏輯等價**態。「邏輯等價」而非逐字節相同之**唯一
|
||||
差異**:`spacing` 規範化之贅餘作者空格不還原(見 I1)——故 `render→revert` 對含 CJK↔西文作者
|
||||
空格之源,還原後語義一致、結構全清,唯該空格已正規化(此差異穩定、不隨 `render`/`revert` 反覆
|
||||
累積)。`revert` 後 DOM 內無任何 `[data-jz]` 殘留(實測驗收成立)。
|
||||
- **I6 冪等與可還原**:每個 pass 對產物打標記供定址,私有所有權憑證才決定還原權限。
|
||||
`revert` 撤回本實例仍有效的產物(wrap→解包、splitoff→併回)及受控屬性,保留作者與
|
||||
其他實例內容。沒有外部修改時,DOM 回到處理前的**邏輯等價**態;`spacing` 正規化的
|
||||
贅餘作者空格不還原(見 I1),此差異不隨反覆 render/revert 累積。
|
||||
外部克隆、替換、刪除後,按產物及來源完整性檢查安全回退,不復活過時文字;
|
||||
不保證恢復歷史快照或清空所有 `[data-jz]`。DOM 標記本身不授予所有權。
|
||||
- **I7 邊界感知**:跨樣式行內元素的鄰接(如 `<strong>是</strong>A`)須能識別並
|
||||
正確處理——由核心 finder 統一提供,各 pass 不自行重複造輪。
|
||||
- **I8 向下相容 v1(已退役)**:相容層曾保障 v1 消費端(build.sh 單檔串接、Nvim
|
||||
@@ -76,7 +77,8 @@ CSS box、observer、瀏覽器量測,以及 TeX node/glue/penalty/macro
|
||||
(見 §3.4),以減少全樹走訪次數;聚合不得犧牲 I6(冪等可還原)與逐功能開關。
|
||||
- **I10 作用域與分塊**:作用範圍可由 `scope.include` 選擇器限定(opt-in);功能集
|
||||
可逐塊覆寫(屬性或 `blocks` 映射),由 pass 在 `collect` 內以 per-node 閘解析
|
||||
(見 §3.6)。CSS 視覺規則須與 JS 作用域同域收斂,不外溢。
|
||||
(見 §3.6)。`scope.include` 只限定 JS 處理;結構樣式直接作用於 `jz-*`,原生間距
|
||||
禁用層固定於 `.juzhen`。呼叫端負責讓容器標記與 JS 作用域對應。
|
||||
|
||||
---
|
||||
|
||||
@@ -105,6 +107,10 @@ jz.disconnect(); // 停止觀察
|
||||
同批移出根的節點與已離根的舊記錄則跳過,不以 `isConnected` 代替作用域判斷。
|
||||
搬入既有塊時,以同批移除來源、私有產物或已知 render 根辨識;先 revert 再 render
|
||||
撤回舊祖先的語言/級別/功能效果。純新增塊直接 render,但插入子樹的快取先失效。
|
||||
手動 `render`/`revert`/`rerender` 在最外層暫停 observer 前,先同步結算 `takeRecords()`
|
||||
中的待交付變化,可能更新其他區塊;隨後才執行手動操作,局部回退仍最後生效。
|
||||
結算舊記錄的錯誤由宿主微任務非同步報告,不成為手動 API 的同步例外;手動操作自己的
|
||||
錯誤仍照常同步拋出。
|
||||
|
||||
**增量粒度契約(下游說明八)**:增量更新須以**塊**為粒度——換塊內容(`textContent`/
|
||||
`innerHTML`)、增刪塊、改分類屬性,皆與全量重繪一致(差分複驗逐位元相同)。**不支持**對聚珍
|
||||
@@ -165,6 +171,7 @@ interface BasePass {
|
||||
|
||||
interface CharifyPass extends BasePass {
|
||||
kind: "charify";
|
||||
prepare?: (ctx: RenderContext) => void;
|
||||
collect(node: Text, ctx: RenderContext): WrapRequest[];
|
||||
}
|
||||
|
||||
@@ -176,7 +183,8 @@ interface StandalonePass extends BasePass {
|
||||
type Pass = CharifyPass | StandalonePass;
|
||||
```
|
||||
|
||||
`CharifyPass` 只收集文本包裝請求;`StandalonePass` 自行執行功能所需的掃描或 layout。
|
||||
`CharifyPass` 可先以 `prepare` 處理跨節點完整原子,再收集普通 Text 的包裝請求;
|
||||
`StandalonePass` 自行執行功能所需的掃描或 layout。
|
||||
兩類皆由同一註冊表管理,且均按 `level` 與功能閘判定是否生效。
|
||||
|
||||
`createJuzhen` 內建一個**有序、可開關**的 pass 註冊表。`render` 依 `order` 執行
|
||||
@@ -247,8 +255,9 @@ Nvim peek/Claude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
|
||||
- `scope.include`:**啟用選擇器**(opt-in 模式)。設定後,**僅處理命中該選擇器之
|
||||
子樹**(如 `".juzhen, [data-juzhen]"`),其餘一概不動——此即「限定作用範圍」。
|
||||
- `scope.avoid`:排除選擇器,與內建 avoid 合併。
|
||||
- **CSS 同域**:`juzhen.css` 之視覺規則一律收斂於同一啟用選擇器(如 `.juzhen` 下),
|
||||
與 JS 作用域一致,杜絕樣式外溢(呼應 I2、§9.1 之禁用層亦限於此域)。
|
||||
- **CSS 作用域**:`scope.include` 不改寫 CSS。`jz-*` 結構樣式直接按元素/class 生效;
|
||||
§9.1 的原生間距禁用層固定於 `.juzhen`。若 JS 用 `.prose` 啟用,呼叫端可用
|
||||
`class="prose juzhen"` 對齊兩者;作者自行建立的 `jz-*` 也會匹配結構樣式。
|
||||
|
||||
**分塊功能選擇**——不同塊啟用不同功能集:
|
||||
|
||||
@@ -281,12 +290,11 @@ Nvim peek/Claude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
|
||||
- **scope.include**:若設啟用選擇器,僅走訪命中之子樹(opt-in,§3.6)。
|
||||
- **featureEnabledFor(node, name)**:解析該節點之有效功能集(§3.6),供各 pass 之
|
||||
`collect` per-node 閘用;結果以元素為鍵快取。
|
||||
- **charify**:把符合條件之字元/字串包進指定 `jz-*` 元素(兩階段:先收集目標、
|
||||
後變更,避免遍歷中改 DOM 失效)。
|
||||
- **邊界感知 replace(I7)**:對「跨相鄰文本節點、可跨樣式行內元素」的邏輯字串
|
||||
做正則 find,回呼決定如何包裝/插入標記。樣式行內元素(`strong/em/a/span/…`)
|
||||
透明穿越;block/pill/avoid 中斷邏輯串。此即 v1 Pass A「剝離樣式收集邏輯文本
|
||||
再反映射」之一般化,提升為可重用引擎。
|
||||
- **文字走訪**:`eachTextNode` 提供受過濾的 Text,charify pass 收集 `WrapRequest`,
|
||||
由 `core/pass.ts` 批次包裝;Finder 本身不提供 charify mutation API。
|
||||
- **邊界與來源映射(I7)**:`collectRuns` 收集跨透明 Text 的邏輯字串及完整來源跨度,
|
||||
`adjacentLogicalChar` 查詢完整鄰字。block/pill/avoid/isolate 等按分類中斷脈絡;
|
||||
正則匹配與間隙回放由功能模組實作,不是 Finder 的泛用 replace/回呼插入 API。
|
||||
- **完整 Unicode 原子**:`collectRuns` 將跨透明 Text 的 surrogate pair 先合成完整碼點,
|
||||
再將 base 與至多一個 variation selector 合為原子;`map.parts` 保留所有來源跨度。
|
||||
間隙、禁則與避孤字共用此映射,不在原子中間建間隙/斷點、不把 selector 另算實義字。
|
||||
@@ -385,8 +393,9 @@ avoid」用組合入口 `isAvoided`(=自身或祖先,階段二歸一,免
|
||||
(`{ cjk?, western?, biaodian? }`)**擴充**,`resolveRuleset(override)` 以**追加**語義合併
|
||||
為最終規則集,置於 `ResolvedOptions.ruleset`。各 pass 由此取分類:
|
||||
|
||||
- `spacing`:`makeRules(ruleset)` 由 `cjk`/`ansAfter`/`ansBefore` **per-instance 編譯**
|
||||
全部間隙正則(createJuzhen 各一次,非每 block);`ALNUM`/`ALPHA`/運算符/括號等結構性
|
||||
- `spacing`:每次 spacing render 開始時,`makeRules(ruleset)` 按該實例的
|
||||
`cjk`/`ansAfter`/`ansBefore` 編譯全部間隙正則,復用於本次各處理塊;
|
||||
`ALNUM`/`ALPHA`/運算符/括號等結構性
|
||||
ASCII 集為固定常數、不隨規則集變。
|
||||
- `jiya`:`classifyBiaodian(ch, ruleset.biaodian)` 決定 charify 與 bd-* 子類。
|
||||
- `jinze`:`anyCjk = RegExp(ruleset.cjk)` 決定詞元邊界之 CJK 判定。
|
||||
@@ -409,21 +418,28 @@ avoid」用組合入口 `isAvoided`(=自身或祖先,階段二歸一,免
|
||||
祖先鏈掃 `data-jz-style` 屬性/`stylePolicy` 選擇器命中,近祖先勝、同層屬性優先於選擇器)
|
||||
> 逐 lang `policy` > 全域 `style` > 內建逐語言預設(`zh-Hant`/`zh-HK` → 全角、`zh-Hans` →
|
||||
開明)。逐元素覆寫供「非段落/UI 元素用半角、段落用全角/開明」等需求(`data-jz-style` 屬性
|
||||
值非法則忽略、回退 lang)。此純為「按元素選樣式」之路由,`banjiao` 半形渲染沿用 `halt`/
|
||||
值非法時只忽略該信號,仍查同層選擇器與祖先;逐元素信號皆缺失才回退語言政策)。
|
||||
此純為「按元素選樣式」之路由,`banjiao` 半形渲染沿用 `halt`/
|
||||
`margin`(§6.3),無新增壓縮邏輯。
|
||||
|
||||
CSS 端對應以 `:lang()` 選擇器落實 lang 層政策(I2/I3);逐元素覆寫屬 JS 端 baseline 判定。
|
||||
語言與逐元素政策均由 JS 判定並轉為半形 class;CSS 按 class 使用 `halt`/`margin` 渲染。
|
||||
`lang.policy` 的鍵是 `zh-Hans`/`zh-Hant`/`ja`/`other` 四個分類,非任意完整語言標籤。
|
||||
|
||||
### 4.4 `dom.ts`——`jz-*` 元素工廠與還原
|
||||
|
||||
`createEl('jz-char', {class, attrs})`、`wrap(node, el)`、`splitAt`、`insertMarker`、
|
||||
冪等標記(`data-jz="<pass>"`)、`revertPass(name, root)`(移除該 pass 之產物、
|
||||
解包 `jz-*`、合併回文本節點並 `normalize()`)。
|
||||
`createJz(ownedElements, tag, pass, kind, opts)` 建立元素、登記私有所有權,並寫入
|
||||
`data-jz`/`data-jz-kind` 供定址。`setOwnedAttribute` 與 `revertOwnedAttribute`/
|
||||
`revertOwnedAttributes` 以共享寫者堆疊管理受控屬性;外部修改或其他實例寫入不被無條件覆蓋。
|
||||
|
||||
`data-jz-kind` 區分產物還原方式:`marker`(純注入,移除)、`wrap`(包裝原內容,解包)、
|
||||
**`splitoff`**(行內元素克隆切分之邊界詞元,見 `core/split.ts`/§6.4)。`revertPass` 分
|
||||
**兩階段**處理:主迴圈逆序解包 marker/wrap,第二階段再把 splitoff 併回前兄弟(同標籤
|
||||
原元素)——順序必要,否則 splitoff 之前兄弟可能仍是 wrap 殼(如 `jz-jinze`)而非原元素。
|
||||
`revertPass(pass, root, ownedElements)` 先驗證本實例所有權與合法 pass/kind/tag 組合。
|
||||
目前接受 `wrap`(包裝原內容)與 **`splitoff`**(行內元素克隆切分之邊界詞元);不提供
|
||||
泛用 `marker` 還原。第一階段逆序解包 wrap,第二階段把 splitoff 併回同標籤前兄弟,
|
||||
最後 normalize 受影響父節點。順序必要,否則 splitoff 前兄弟可能仍是 wrap 殼。
|
||||
|
||||
`recordUnwrappedParent`/`resolveUnwrappedParent` 記錄及解析合法產物的受控解包鏈,
|
||||
供跨節點來源回退使用;重用空殼會使舊位置失效,重定向環不作為文字恢復依據。
|
||||
包裝請求由 `core/pass.ts` 執行,安全行內切分位於 `core/split.ts`;本模組沒有
|
||||
`createEl`/`wrap`/`splitAt`/`insertMarker` 等泛用變更函數。
|
||||
|
||||
---
|
||||
|
||||
@@ -584,7 +600,8 @@ class 約定以現有 CSS/pass 為準:標點採 `bd-open`/`bd-close`/`bd
|
||||
`halt` 收的是字身寬度、由字型按字形正確定位(簡左/繁中/括號偏側皆對),故
|
||||
不重疊。`font-feature-settings:"halt"` 各引擎一致(當初疑慮之不一致者為**自動**
|
||||
的 `text-spacing-trim`/`chws`,非顯式 `halt`);缺 `halt` 之字型優雅降級為全形。
|
||||
鄰接/行端之「收哪一字」之**決策**仍由 `blankSides` 邏輯定,渲染統一為 `halt`。
|
||||
鄰接/行端之「收哪一字」之**決策**仍由 `blankSides` 邏輯定;預設以 `halt` 渲染,
|
||||
缺半形特性的字型可採下述逐字 `margin` 後備。
|
||||
- **句末標點集含全角句點 `.`(下游回饋)**:`BD_STOP` 為 `。.!?`——除表意句號 `。`
|
||||
(U+3002)外,納入**全角句點 `.`**(U+FF0E)。實測 Noto CJK SC/TC 之 `halt`(GPOS
|
||||
SinglePos 調 advance)皆覆蓋 `.`、挤壓收 0.5em,與 `。` 一致;`inkBias` 同步補 `.`
|
||||
@@ -617,7 +634,9 @@ class 約定以現有 CSS/pass 為準:標點採 `bd-open`/`bd-close`/`bd
|
||||
依**字身墨色中心**給出 `left|center|right|full`(簡體點號偏左、繁體居中;彎引號
|
||||
`“”`/角括號 `「」`/尖括號 `〈〉` 墨強偏一側→開 right、閉 left;圓方書名括號
|
||||
`()【】《》…` 近中→center),charify 時標為 `jz-ink-{left,center,right}`。消費端可
|
||||
經 `jiya.bias` 逐 lang 逐字覆寫;配字工作流與量測工具 `tools/measure-bias.py` 見 README。
|
||||
經 `jiya.bias` 逐語言分類、逐字覆寫;`full` 不套 margin 的 0.5em 盒寬,保留全形。
|
||||
**此逐字字型相容方案仍是當前支援路徑**;配字工作流、JSON 範例與量測工具
|
||||
`tools/measure-bias.py` 見 README,不屬已移除的負 letter-spacing/標點懸掛機制。
|
||||
- **激活與粒度(I3/I10)**:最近有效 `data-jz-halfwidth="halt|margin"` 屬性透過
|
||||
可繼承 CSS 變數決定模式;`render()` 在全域 margin 時自動掛於 root。可在任意祖先
|
||||
逐區塊/逐語言指定並交替巢狀,切回 halt 會撤銷 margin 盒寬、內盒及偏移。bias
|
||||
@@ -704,20 +723,24 @@ class 約定以現有 CSS/pass 為準:標點採 `bd-open`/`bd-close`/`bd
|
||||
直覺:文本級=「字符級排版」(間隙、標點形態);段落級=「行/段級排版」(換行、行端、段末)。
|
||||
|
||||
**標記 API(下游)**:
|
||||
- 預設推斷:塊級元素(`blockTags`:p/div/li/td…)→ **段落級(全功能)**。
|
||||
|
||||
- 級別由自身向上查最近有效信號,不依標籤名推斷;沒有任何信號時預設 **paragraph**。
|
||||
- 顯式降級:`data-jz-level="text"` 於元素/祖先 → 該子樹**僅文本級**(段落級功能自動關);
|
||||
`data-jz-level="paragraph"`(或不標)→ 全功能。
|
||||
子元素可用 `data-jz-level="paragraph"` 重新允許段落級功能,但仍受全域功能開關、
|
||||
逐元素功能閘與作用域限制。不標記的子元素繼承祖先信號,不會自動重新啟用全功能。
|
||||
- 選項 `level?: { text?: string }`:選擇器一鍵標記(如 `level:{ text: "h1,h2,h3,button,.ui" }`)。
|
||||
- 典型:標題/按鈕/UI 文字標 **text-level**(要間隙與標點半形、不要避孤字/避頭尾);
|
||||
正文 `<p>` 預設全功能。
|
||||
|
||||
**實現**:
|
||||
|
||||
- 每個 pass 加元數據 `level: "text" | "paragraph"`。
|
||||
- `finder.levelFor(el)`:查 `data-jz-level` 祖先 + 選項 `level.text` 選擇器 + 預設(塊→段落)。
|
||||
- `finder.levelFor(el)`:從自身向上查;每層先取合法 `data-jz-level`,再查 `level.text`
|
||||
選擇器,第一個有效信號勝出;皆無才回退 paragraph。非法屬性值繼續查找。
|
||||
- gate:段落級 pass 對 text-level 元素跳過;文本級 pass 不受限。與現有 `blocks`/
|
||||
`featureEnabledFor` 疊加(level=粗粒度語義組先判,blocks=細粒度逐功能後調)。
|
||||
- **文本級功能須支持非塊/單元素**:`spacing` 現用 `eachBlock`,須確認 scope root 為 inline/
|
||||
單元素時亦能處理(或放寬走訪),使單行標題等之中西間隙、標點半形生效。
|
||||
- **文本級功能支持非塊/單元素**:`spacing` 在逐塊處理後,補做未被塊覆蓋的行內 root
|
||||
及 `scope.include` 命中的行內子樹,避免重複處理;標點 charify 也可走訪行內 root。
|
||||
|
||||
**與本批關係**:分級已落地(pass 標 level、`levelFor`、`data-jz-level`/選項);`orphan`
|
||||
等段落級 pass 只作用於段落級元素、跳過 text-level 者。`hanging` 未註冊為 pass。
|
||||
@@ -739,7 +762,7 @@ class 約定以現有 CSS/pass 為準:標點採 `bd-open`/`bd-close`/`bd
|
||||
| 機制 | 作用層 | 唯一職責 | 手段 | 狀態 |
|
||||
|---|---|---|---|---|
|
||||
| 禁則(§6.4 jinze) | **斷行層** | 把標點趕到正確的邊(點號/閉類→行末、開類→行首;連續標點不拆) | nowrap `jz-jinze` | 已實作 |
|
||||
| 行端半形(lineedge 現有) | **渲染層·紧排** | 行首開類/行末閉類**收半形** | `jz-half-le`(halt) | 已實作(將併入行端模式) |
|
||||
| 行端半形(lineedge 現有) | **渲染層·紧排** | 行首開類/行末閉類**收半形** | `jz-half-le`(halt/margin) | 已實作 |
|
||||
| 標點懸掛 | **渲染層·凸出** | 行末點號/閉類**右凸**、行首開類**左凸**出版心 | ~~負 `margin`~~ | ❌ 已移除(機制級死路,見 6.5.6) |
|
||||
| 垂懸字避免 | **斷行層** | 段末行 **CJK 實義字數 ≥ N** | nowrap `jz-orphan` | 已實作 |
|
||||
|
||||
@@ -761,7 +784,7 @@ class 約定以現有 CSS/pass 為準:標點採 `bd-open`/`bd-close`/`bd
|
||||
- **保證(成功建立尾部綁定時,免測 layout)**:該整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型/
|
||||
瀏覽器成立。平時無害(末行本多字時不改變),僅末行將塌為 <N 字時「拉字下來」。
|
||||
- **選項**:`orphan?: boolean | { chars?: number }`(feature gate;**預設開 chars=2**;per-block
|
||||
經 `blocks`/`data-jz`;段落級,`data-jz-level="text"` 子樹跳過)。lang 無關。
|
||||
經 `blocks`/`data-juzhen`/`data-juzhen-off`;段落級,`data-jz-level="text"` 子樹跳過)。lang 無關。
|
||||
- **邊界**:avoid/text/`orphan` 關閉/`isSkipped` 區域清空先前計數,只綁其後的合法
|
||||
段末區域;不足 N 字則不綁。完整碼點及 base+VS 只算一個字。pill 不計內部字,仍可
|
||||
作完整外部單元參與綁定;不可切且含排除內容的容器不退化整綁。極窄容器(<N 字寬)
|
||||
@@ -920,8 +943,9 @@ order `90 jiyaLineEdge`,`revert` 清 `jz-half-le`。純版面、jsdom 跳過
|
||||
2. `jz-char` 設 `display: inline-block`:使其成為 justify 的**單一原子項**,內部
|
||||
不開伸縮 gap,標點與其字面留白同屬一項,對齊伸縮只落在**項與項之間** → 標點
|
||||
只貢獻一份。
|
||||
3. **開明式**下,`jz-inner` 以負 letter-spacing 擠去半形留白,該項本身即半形,
|
||||
justify 一份 gap 即足。
|
||||
3. **開明式**下,JS 為可壓縮標點加半形 class;預設由 `jz-inner` 的 OpenType `halt`
|
||||
收 advance。缺半形特性的字型可用 `margin` 後備:0.5em 外盒搭配逐字 `jiya.bias`
|
||||
偏側定位(§6.3)。原子內部不另開 justify 伸縮量;舊負 letter-spacing 方案不再使用。
|
||||
4. **全角式**下,留白保留於原子項內,仍只算一份;以 `jz-jinze` 綁定確保不在留白
|
||||
側額外開機會點。
|
||||
|
||||
@@ -949,8 +973,8 @@ order `90 jiyaLineEdge`,`revert` 清 `jz-half-le`。純版面、jsdom 跳過
|
||||
- `text-indent: 0`——段落首行縮排傳入後,每原子內部首行各縮排一次,shrink-to-fit 寬膨脹為
|
||||
`縮排量+字形`,標點附近冒出巨大間距。實測:歸零後段落首行縮排仍保持 2em,原子寬由 ~3em
|
||||
回到 0.5em/1em。
|
||||
- `hanging-punctuation: none`——同屬區塊容器首/末行機制,每原子各自懸掛自身標點。Chrome
|
||||
未實作(測不出)、Safari 會觸發,且與規劃中之「標點懸掛」(§任務 6)相衝,故按機制一併歸零。
|
||||
- `hanging-punctuation: none`——避免區塊首/末行機制在每個標點原子內重複套用。
|
||||
當前管線沒有標點懸掛 pass;段落保留此屬性不代表 inline-block 內的受管標點可以懸掛。
|
||||
|
||||
**不歸零者**(實測不洩漏或本應逐字穿透):`letter-spacing`/`word-spacing`(原子邊界處理
|
||||
一致、無翻倍,實測 delta 與基線同);`text-align`/`text-align-last`/`text-justify`
|
||||
@@ -1013,10 +1037,10 @@ src/
|
||||
core/
|
||||
pass.ts 兩類 pass 之分組、排序與管線執行器
|
||||
cross-atom.ts 跨 Text 標點原子搬移/私有來源記錄/回退
|
||||
finder.ts 遍歷/avoid/charify/邊界感知與跨節點 run
|
||||
finder.ts 遍歷/avoid/功能閘/鄰字與跨節點原子映射
|
||||
unicode.ts 字元類 + 標點子類 + 規則正則表
|
||||
locale.ts 有效 lang / 分類 / 全角開明政策
|
||||
dom.ts jz-* 工廠 / ownership / wrap / revert
|
||||
dom.ts jz-* 工廠 / 所有權與屬性寫者 / 還原及受控解包鏈
|
||||
split.ts 禁則/垂懸字之行內元素邊界切分
|
||||
typeset/
|
||||
spacing.ts 中西間隙
|
||||
@@ -1029,9 +1053,10 @@ src/
|
||||
css/
|
||||
juzhen.css 入口(@import 各 partial)
|
||||
_normalize.css _spacing.css _jiya.css _jinze.css _orphan.css
|
||||
test/ jsdom DOM 正確性測試
|
||||
demo/ 瀏覽器 layout/justify/簡繁 目視驗證頁
|
||||
build.mjs esbuild:ESM + IIFE + CSS;tsc:d.ts
|
||||
test/ jsdom DOM 測試 + 原生 WKWebView Swift 宿主/runner
|
||||
demo/ layout/justify/簡繁 目視頁 + e2e.html 自動斷言頁
|
||||
build.mjs esbuild:ESM + IIFE + CSS
|
||||
package.json npm build 串聯 build.mjs 與 tsc 聲明生成
|
||||
```
|
||||
|
||||
`biaodian.ts`/`emphasis.ts`/`ruby.ts`/`hanging.ts` 及同名 CSS partial 均不存在;
|
||||
@@ -1042,12 +1067,13 @@ build.mjs esbuild:ESM + IIFE + CSS;tsc:d.ts
|
||||
## 11. 構建與發佈
|
||||
|
||||
- **源碼**:TypeScript(strict),模組化。
|
||||
- **構建**:`build.mjs` 以 esbuild 產出
|
||||
- **JS/CSS 構建**:`node build.mjs` 以 esbuild 產出
|
||||
- `dist/juzhen.mjs`(ESM,供打包器/TS)
|
||||
- `dist/juzhen.iife.js`(IIFE,全域 `Juzhen`,原生 `<script>` 直跑——保留
|
||||
build.sh/Nvim peek 之單檔串接消費)
|
||||
- `dist/juzhen.css`(合併之樣式)
|
||||
- `tsc --emitDeclarationOnly` → `dist/index.d.ts`
|
||||
- **完整構建**:`npm run build` 先執行 `node build.mjs`,再執行
|
||||
`tsc --emitDeclarationOnly` → `dist/index.d.ts` 及各模組型別宣告。
|
||||
- **發佈物**:`dist/` 提交入庫(消費端可直接取單檔/CSS)。
|
||||
|
||||
---
|
||||
@@ -1056,10 +1082,15 @@ build.mjs esbuild:ESM + IIFE + CSS;tsc:d.ts
|
||||
|
||||
- **jsdom(自動)**:驗證 DOM 變換——包裝結構、`bd-*` class、邊界處理、冪等、
|
||||
`revert` 還原、copy-clean(`textContent` 不被注入污染)、lang 政策分支。
|
||||
- **瀏覽器(目視,demo 頁)**:layout 相關**無法**於 jsdom 驗證——justify 單份
|
||||
間距、擠壓視覺量、行端折疊、inline-block 基線。demo 頁載 Noto CJK,簡繁
|
||||
並列、可切 justify、附選取/複製測試區,於 Chrome/Safari/FF 目視核對。
|
||||
- 文件明確標注哪些結論來自自動測試、哪些待瀏覽器目視。
|
||||
- **原生 WKWebView(自動)**:`npm run test:wkwebview` 需 macOS、Xcode 與 GUI 會話;
|
||||
runner 編譯 Swift 宿主並載入 `demo/e2e.html`,驗證真實行盒、幾何、計算樣式、
|
||||
Selection 及 observer/layout 生命週期。此命令使用現有 `dist`,不自動構建;
|
||||
修改源碼後應先 `npm run build`。jsdom 本身不提供真實版面量測。
|
||||
- **跨引擎目視(demo 頁)**:檢查擠壓墨色、基線、字型適配、justify 和寬度變化等。
|
||||
demo 頁簡繁並列、可切 justify、附選取/複製測試區;Chrome/Safari/Firefox 是
|
||||
待逐環境執行的驗證路線,WKWebView 通過不代表三引擎目視或真實下游頁面已通過。
|
||||
- 驗證記錄須綁定實際快照與環境,分別標示 DOM、原生幾何與目視證據;已知交付記錄
|
||||
見 `UPDATES.md`,不能由測試入口存在推定當前驗收完成。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -93,7 +93,8 @@ import { createJuzhen } from "cjk-autospace";
|
||||
import "cjk-autospace/css";
|
||||
|
||||
const jz = createJuzhen({ lang: { default: "zh-Hant" } });
|
||||
jz.render(document.querySelector("main"));
|
||||
const main = document.querySelector("main");
|
||||
if (main) { jz.render(main); }
|
||||
```
|
||||
|
||||
**JS 與 CSS 缺一不可**:JS 只注入 `jz-*` 結構,所有視覺尺寸(間隙寬度、擠壓量、
|
||||
@@ -145,11 +146,12 @@ jz.observe(document.body); // 之後 DOM 變動即自動增量恢復
|
||||
> 器之固有限制(任何外科式文本 patch 之框架皆會與注入後之 DOM 失步)、非缺陷——聚珍對當前
|
||||
> DOM 之處理始終自洽。欲改文字,以塊為單位替換內容即可。
|
||||
|
||||
> **`revert` 之範圍**:`revert` 乾淨移除聚珍注入之全部結構(`jz-*`/`data-jz-*`),DOM 回到**邏輯
|
||||
> 等價**態;但**不還原** `spacing` 依契約規範化之贅餘作者空格(CJK↔西文吸收為 margin 間隙、
|
||||
> CJK↔CJK 剝除;見上表「中西間隙」)。即 `render→revert` 對含 CJK↔西文作者空格之源,還原後語義
|
||||
> 一致、無 `jz-*` 殘留,唯該空格已正規化(此差異穩定、不隨反覆 render/revert 累積)。若消費端需
|
||||
> 保留原始作者空格以供編輯,應自存原文、勿以 `revert` 當「還原到未處理源碼」。
|
||||
> **`revert` 之範圍**:撤回本實例仍持有所有權、且符合產物與來源完整性檢查的結構及屬性,
|
||||
> 保留作者標記與其他實例的產物。沒有外部修改時,DOM 回到處理前的**邏輯等價**態;但
|
||||
> **不還原** `spacing` 依契約規範化之贅餘作者空格(CJK↔西文吸收為 margin 間隙、
|
||||
> CJK↔CJK 剝除;見後面的「中西間隙」功能表)。此差異穩定、不隨反覆 render/revert 累積。
|
||||
> 外部克隆、替換或刪除後,以作者當前內容為準,不保證恢復歷史快照或清空所有 `jz-*`。
|
||||
> 若消費端需保留原始作者空格以供編輯,應自存原文、勿以 `revert` 當「還原到未處理源碼」。
|
||||
|
||||
外部克隆/替換/刪除跨節點載體後,`revert` 保留作者當前內容,不補回已刪文字;
|
||||
克隆不繼承本實例所有權。欲修改原文,先 `revert` 再修改,或直接替換整塊內容。
|
||||
@@ -217,7 +219,7 @@ createJuzhen({
|
||||
|---|---|---|---|
|
||||
| `lang.default` | string | `"zh-Hant"` | 無 `lang` 祖先時之預設語言標籤 |
|
||||
| `lang.style` | `quanjiao|kaiming|banjiao` | 逐語言內建(繁→全角、簡→開明) | **全域政策一鍵覆寫** |
|
||||
| `lang.policy` | `Record<lang, style>` | `{}` | 逐 lang 政策 |
|
||||
| `lang.policy` | `Partial<Record<LangClass, PunctStyle>>` | `{}` | 按語言分類覆寫:鍵僅為 `zh-Hans`、`zh-Hant`、`ja`、`other`;如 `zh-TW` 先歸入 `zh-Hant`,不直接作為鍵 |
|
||||
| `lang.stylePolicy` | `{selector,style}[]` | `[]` | **逐元素樣式覆寫**(選擇器命中之子樹用指定樣式;如 `[{selector:"h1,button,.ui",style:"banjiao"}]`);配合 `data-jz-style` 屬性,優先於 lang |
|
||||
|
||||
**作用域**
|
||||
@@ -248,8 +250,8 @@ createJuzhen({
|
||||
|---|---|---|---|
|
||||
| `pillSelector` | CSS 選擇器 | `"code, kbd"` | 整體元素(內部不可見、兩端補隙) |
|
||||
| `isolateSelector` | CSS 選擇器 | `"mark"`(`""` 停用) | 隔離元素(內部照常、兩端補隙) |
|
||||
| `styleInlines` | 標籤名[] | 27 個標準行內標籤 | **透明穿越白名單**(未列之行內標籤=邊界) |
|
||||
| `blockTags` | 標籤名[] | 36 個塊標籤 | 塊級邊界集 |
|
||||
| `styleInlines` | 標籤名[] | 28 個標準行內標籤 | **透明穿越白名單**(未列之行內標籤=邊界) |
|
||||
| `blockTags` | 標籤名[] | 43 個塊標籤 | 塊級邊界集 |
|
||||
| `skipTags` | 標籤名[] | `PRE,SAMP,TT,VAR,SCRIPT,STYLE,TEXTAREA,INPUT` | avoid 標籤集(**不含 CODE/KBD**,由 pill 涵蓋) |
|
||||
| `skipAttribute` | string | `null` | 自訂「跳過」屬性名(命中即 avoid) |
|
||||
| `isSkipped` | `(node)=>bool` | `null` | 自訂跳過謂詞(函數級排除鉤子) |
|
||||
@@ -291,8 +293,9 @@ createJuzhen({
|
||||
```
|
||||
|
||||
優先序:**逐元素覆寫**(`data-jz-style` 屬性/`stylePolicy` 選擇器,**近祖先勝、同層屬性優先於
|
||||
選擇器**)> `lang.policy` > `lang.style` > 內建逐語言預設。屬性值非法(拼錯)則忽略、回退
|
||||
lang。半角式渲染沿用既有 `halt`/`margin` 機制(見下節),本功能只做「按元素選樣式」、無新增
|
||||
選擇器**)> `lang.policy` > `lang.style` > 內建逐語言預設。屬性值非法(拼錯)只忽略該信號,
|
||||
仍查同層 `stylePolicy` 選擇器與祖先;沒有任何逐元素信號時才回退語言政策。
|
||||
半角式渲染沿用既有 `halt`/`margin` 機制(見下節),本功能只做「按元素選樣式」、無新增
|
||||
渲染邏輯。
|
||||
|
||||
### 行內元素三分類:透明/隔離/整體
|
||||
@@ -487,6 +490,10 @@ CSS 皆刪)。`hanging` 選項仍被接受(API 相容)但**無任何效果
|
||||
|
||||
## 標點半形:`halt` 預設與 `margin` 後備
|
||||
|
||||
**缺半形特性字型的逐字相容方案仍保留**:`margin` 後備搭配 `jiya.bias`,可按語言分類、
|
||||
逐標點指定 `left`/`center`/`right`/`full`。它與字型自帶的 `halt` 是兩條渲染路徑;
|
||||
偏側覆寫、量測工具與目視微調流程見本節,不因移除舊負 letter-spacing 方案而取消。
|
||||
|
||||
開明/半角式把標點收成「半形」,有兩種渲染機制:
|
||||
|
||||
| 機制 | 設定 | 原理 | 適用 |
|
||||
@@ -605,11 +612,11 @@ JS 只注入 `jz-*` 結構,**所有視覺尺寸在 `juzhen.css`**——故 CSS
|
||||
關閉原生 `text-autospace`(避免與受管間隙重複作用);不設定 `text-spacing-trim`,
|
||||
間隙不注入空白字元;僅跨節點 IVS gap 之 `U+200B ::after`
|
||||
設 `user-select:none`,避免該斷行提示進入選取/複製。
|
||||
8. **段落屬性照常設、原子透明**:聚珍把標點拆成 inline-block 原子,但已確保這些原子對
|
||||
消費端段落樣式透明——可在段落正常設 `text-indent`(首行縮排)、`hanging-punctuation`、
|
||||
`text-decoration`(下劃線)等;庫內已歸零會被原子重複套用之繼承屬性、並令原子承接段落
|
||||
裝飾,故首行縮排正常、下劃線連續不斷,無需任何額外配置(機制見 ARCHITECTURE「原子透明
|
||||
原則」)。
|
||||
8. **段落縮排與裝飾**:聚珍把標點拆成 inline-block 原子,於原子上歸零 `text-indent`,
|
||||
避免段落首行縮排被每個原子重複套用;原子也承接 `text-decoration` 裝飾。
|
||||
可在段落設定縮排與下劃線(機制見 ARCHITECTURE「原子透明原則」)。
|
||||
`hanging-punctuation` 在原子上設為 `none`;當前管線不提供標點懸掛,不能由此推定
|
||||
段落設定該屬性便會使受管標點出版心。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+6
-2
@@ -16,6 +16,9 @@
|
||||
切回 halt 也會殘留 inline-block 內盒。現在由最近有效標記決定模式,可交替巢狀,
|
||||
切回 halt 同時復原內盒與偏移。margin 的偏側位移僅作用於已壓縮標點;全形標點不再偏移。
|
||||
|
||||
既有缺半形特性字型的逐字相容方案仍保留:`margin` 後備搭配 `jiya.bias`,可按語言分類、
|
||||
逐標點選 `left`/`center`/`right`/`full`;字型量測與目視微調流程見 README。
|
||||
|
||||
**受影響者**:混用含 halt 與缺 halt 字型、巢狀半形模式,或 margin 區域含全形標點的消費端。
|
||||
標記與呼叫方式無需更換。若曾加 CSS workaround 抵銷舊版行為,更新後須確認其是否仍需要。
|
||||
|
||||
@@ -114,6 +117,7 @@ N 字,或不可切容器還含排除內容時不綁。pill 仍可作完整單
|
||||
353 項 Node 測試、發佈構建及原生 WKWebView 53 項驗收;layout/數值回歸見
|
||||
`test/layout-lifecycle.test.mjs` 與 `test/numeric-options.test.mjs`;觀察根及跨節點標點
|
||||
回歸見 `test/observer-boundaries.test.mjs` 與 `test/punctuation-atoms.test.mjs`。
|
||||
系統交互新增 42 項回歸見 `test/systematic-interactions.test.mjs`;另有 32 組功能
|
||||
開關×10 類結構共 320 個 DOM 組合及 splitoff 多實例 36 個組合通過。
|
||||
系統交互新增 42 項回歸見 `test/systematic-interactions.test.mjs`。修復過程中的中間快照
|
||||
另通過 32 組功能開關×10 類結構共 320 個 DOM 組合及 splitoff 多實例 36 個組合;
|
||||
這兩組為調查階段證據,不列為最終提交的獨立復驗。最終快照驗收為上述 353/53 項。
|
||||
真實下游頁面仍須自行驗證其字型與版面。
|
||||
|
||||
Reference in New Issue
Block a user