feat: Pass D 開明式標點擠壓(句內點號半形)

句內點號(,、;:)逐字包進 <span class="cjk-squeeze">,配合消費端 CSS
`font-feature-settings: "halt"` 擠成半形;句末點號(。?!)保持全形——
此即開明式。span 內含真標點字元,複製不污染原文。

clreq 之「連續標點擠壓」與「行端壓縮」屬 layout-aware 規則,交由原生
`text-spacing-trim` 處理(Chrome 123+ 預設生效,要求字型有 halt/chws),
JS 不涉入以免重複擠壓。真·行尾懸掛(hanging-punctuation)僅 Safari 支援
且繁體橫排不宜,故不納入配方。

預設啟用,支援 `langWhitelist` 依 lang 前綴限定擠壓範圍、`marks` 與
`squeezeClass` 自訂。含 16 項 jsdom DOM 測試。
This commit is contained in:
2026-06-01 18:53:50 +08:00
parent a5faec5abf
commit 82c2d22535
3 changed files with 204 additions and 7 deletions
+36
View File
@@ -56,6 +56,42 @@ export interface CjkAutospaceOptions {
/** 包裝 span 之 `lang` 屬性值。預設 `"en"`。 */
lang?: string;
};
/**
* Pass D(**預設啟用**):開明式標點擠壓。把句內點號(`,、;:`)包進
* `<span class="…">`,配合消費端 CSS `font-feature-settings: "halt"` 擠
* 成半形;句末點號(`。?!`)保持全形——此即「開明式」。span 內含真
* 標點字元本身,故 Copy / Paste 返回原文不變。
*
* `font-feature-settings: "halt"` 套整個元素只會把所有標點變半形(半角
* 式),故必須逐字選擇性包裝——這是 CSS 表達不了、JS 不可替代的一層。
* clreq 之「連續標點擠壓」與「行端壓縮」交由原生 CSS(layout-aware):
*
* ```css
* .cjk-squeeze { font-feature-settings: "halt" 1; } // 句內點號半形
* .article { text-spacing-trim: normal; } // 連續標點 + 行端壓縮
* ```
*
* `text-spacing-trim` 於 Chrome 123+ 預設生效(要求字型有 `halt`/`chws`
* Noto CJK 滿足);`hanging-punctuation`(真·懸掛)僅 Safari 支援且繁體
* 橫排不宜,故不納入配方。
*
* 傳 `false` 顯式關閉;`true` 或省略等同預設(marks `["","、","",""]`、
* class `"cjk-squeeze"`、不限語言)。
*/
punctuationSqueeze?: boolean | {
/** 包裝 span 之 class 名。預設 `"cjk-squeeze"`。 */
squeezeClass?: string;
/** 要擠壓之標點字元(單字元)陣列。預設句內點號 `["", "、", "", ""]`。 */
marks?: readonly string[];
/**
* BCP-47 語言前綴白名單。非空時僅擠壓最近祖先 `lang` 前綴命中之文本
* `"zh"` 命中 `"zh-Hant"`;無 `lang` 祖先視為不命中)。空陣列或省略
* 則不限語言。例:`["zh-Hans"]` 限定簡體(開明式於簡體字型下字面位
* 於左下角,擠壓最自然;繁體點號居中,視覺略異)。
*/
langWhitelist?: readonly string[];
};
}
export interface CjkAutospaceInstance {