feat(levelmark): 塊級分類 CSS 鉤子 data-jz-block-level+增量塊粒度契約(下游建議七/說明八)

建議七:新增 levelMark pass(standalone,order 10,恆開)——render 時把 resolved
功能級別寫回「直接承載可處理文本」之塊級元素:data-jz-block-level="paragraph|text",
revert 全數移除(I6 之 data-jz-* 清單涵蓋)。消費端段落級 CSS(首要 text-align:
justify)自此與 jinze/orphan 共用單一真相源,免另立必然漂移之選擇器白名單。

- 僅標直接承載文本之塊:純容器(body/ul/table…,直接文本僅空白)不標——否則
  body 恆判 paragraph、justify 鉤子經繼承污染全頁;此集合恰為段落級 pass 實際
  作用之塊集。avoid 子樹/pill 內部文本不計,未被處理之塊一致不標。
- 輸入/輸出分離:作者輸入 data-jz-level 只讀不寫;輸出屬性本庫絕不讀取、亦不在
  C2 OBSERVE_ATTRS 白名單(外部改動不觸發);增量路徑 revert 即清、render 即重標。
- 實現:一次 eachTextNode 走訪+短程上攀定塊(per-run 快取),O(文本);levelFor
  已記憶化。上攀止於 ctx.root,不越界外標。

說明八:README/ARCHITECTURE §3.1 明載增量粒度契約——增量須以塊為粒度(換塊
內容、增刪塊、改分類屬性皆與全量重繪一致);不支持對聚珍已切分文本節點之外科式
characterData 直改(charify 以 fragment 替換原節點,舊引用已脫離文檔)——後處理
排版器之固有限制、非缺陷,以塊為單位替換內容即可。

測試 140→145(標記/純容器不標、text 解析三路(選擇器/屬性/祖先)、avoid/
pill 不標、revert 全清含 root、C2 class 翻轉自動刷新);tsc 聲明構建通過;
headless Chrome 整管線煙測零報錯、段落屬性實際落 DOM。
This commit is contained in:
2026-07-16 16:42:56 +08:00
parent 2f04ea4085
commit 8ee9895247
8 changed files with 345 additions and 5 deletions
+20
View File
@@ -92,6 +92,14 @@ jz.disconnect(); // 停止觀察
**暫停觀察**,故 juzhen 自身之 jz-* 注入絕不自觸發。實測編輯 400 段中之一段,局部恢復較全樹快數
百倍。**元素變化正確性**見 §4.1 末「快取生命週期與失效」。
**增量粒度契約(下游說明八)**:增量更新須以**塊**為粒度——換塊內容(`textContent`
`innerHTML`)、增刪塊、改分類屬性,皆與全量重繪一致(差分複驗逐位元相同)。**不支持**對聚珍
已切分之文本節點做外科式 `characterData` 直改(如持有 render **前**之 `p.firstChild` 引用、
事後直改其 `.data`):charify 以 fragment **替換**原文本節點(§3.4),舊引用已脫離文檔或僅指
碎片,直改令 `revert` 合併出之內容偏離作者意圖。此為後處理排版器之固有限制、非缺陷——聚珍對
當前 DOM 之處理始終自洽;外科式文本 patch 之框架(vdom 等)須以塊為單位替換,或對受管區域
`revert` 後再 patch。
`options` 形如:
```
@@ -654,6 +662,18 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
**與本批關係**:先落地分級(pass 標 level、`levelFor`、`data-jz-level`/選項)→ orphanhanging
註冊為段落級,自動只作用段落級元素、跳過 text-level 者。實作順序插於 6.5.5 之首。
**Resolved 分類之 CSS 鉤子(下游建議七,`typeset/levelmark.ts`)**:消費端之段落級 CSS(首要
`text-align:justify`)語義上與段落級 pass 應作用於**同一集合**,但 level 判定原僅存內部快取,
消費端只能另立一份選擇器白名單、兩份分類必然漂移(實例:`.callout` 綁了避頭尾卻不在 justify
名單)。`levelMark` passstandaloneorder 10,恆開)於 render 時把 resolved 級別寫回塊級元素:
`data-jz-block-level="paragraph|text"``revert` 全數移除(I6)。**僅標「直接承載可處理文本」
之塊**(存在非空白文本節點、其最近塊祖先即該塊、非 avoid/pill 內/域外)——純容器(body/ul
/table…)不標,否則 body 恆被判 paragraph、justify 鉤子經繼承污染全頁;此集合恰為段落級 pass
實際作用之塊集(`collectRuns` 對純容器收不到 run)。**輸入/輸出分離**:作者輸入 `data-jz-level`
只讀不寫;輸出屬性本庫絕不讀取、亦不在 C2 `OBSERVE_ATTRS` 白名單(外部改動不觸發重處理);
增量路徑(rerenderobserverevert 即清、render 即重標,天然刷新。本庫只供分類、不介入樣式
(justify 非段落之純函數——窄欄邊注可 opt-out,由消費端 CSS 決定)。
#### 6.5.0 四機制之分工與邊界(核心約定,實作前必讀)
| 機制 | 作用層 | 唯一職責 | 手段 | 狀態 |