feat: 逐元素標點樣式覆寫 data-jz-style + lang.stylePolicy(非段落用半角式等)

下游需求:非段落/特定範圍元素用半角式(banjiao),段落用全角/開明。原標點樣式僅由 lang
決定(lang.policy/lang.style),無逐元素覆寫。新增與 data-jz-level/level.text 同構之逐元素樣式
機制(banjiao 渲染早已就緒,此為純路由、無新壓縮邏輯、無新 CSS)。

設置格式(供下游):
・HTML 屬性:data-jz-style="banjiao|kaiming|quanjiao"——標於元素或其祖先,該子樹用此樣式。
・選項:lang: { stylePolicy: [{ selector, style }] }——如
  [{ selector: "h1,h2,button,.ui", style: "banjiao" }]。
・優先序:逐元素覆寫(近祖先勝、同層屬性優先於選擇器)> lang.policy > lang.style > 內建。

實作:resolveStyle 先查 resolveStyleOverride(自身及祖先鏈掃 data-jz-style 屬性/stylePolicy
選擇器命中),無則回退 lang。屬性值非法(拼錯)則忽略、續回退。types.ts 補 lang.stylePolicy
+導出 StyleRule;index.ts 正規化(stylePolicy 預設 [])。

冒烟三例通過(屬性 banjiao/選擇器 banjiao/屬性覆蓋選擇器);既有 121 測試無回歸(stylePolicy
預設空、行為不變)。回歸測試+文檔隨後補(e2e 階段)。
This commit is contained in:
2026-07-11 01:42:31 +08:00
parent 4f84d31785
commit c00fb3e482
7 changed files with 134 additions and 14 deletions
+27 -1
View File
@@ -637,7 +637,32 @@ function styleFor(langClass, config) {
}
return DEFAULT_POLICY[langClass];
}
function isPunctStyle(v) {
return v === "quanjiao" || v === "kaiming" || v === "banjiao";
}
function resolveStyleOverride(node, stylePolicy) {
let el = node.nodeType === 1 ? node : node.parentElement;
while (el) {
const attr = el.getAttribute ? el.getAttribute("data-jz-style") : null;
if (isPunctStyle(attr)) {
return attr;
}
if (stylePolicy) {
for (const rule of stylePolicy) {
if (rule.selector && el.matches && el.matches(rule.selector)) {
return rule.style;
}
}
}
el = el.parentElement;
}
return null;
}
function resolveStyle(node, config) {
const override = resolveStyleOverride(node, config.stylePolicy);
if (override) {
return override;
}
const lang = effectiveLang(node, config.default);
return styleFor(classify(lang), config);
}
@@ -2028,7 +2053,8 @@ function normalizeOptions(opts = {}) {
locale: {
default: langOpt.default || "zh-Hant",
...langOpt.style ? { style: langOpt.style } : {},
policy: langOpt.policy || {}
policy: langOpt.policy || {},
stylePolicy: Array.isArray(langOpt.stylePolicy) ? langOpt.stylePolicy.slice() : []
},
ruleset: resolveRuleset(opts.charClass),
justifyAtoms: opts.justifyAtoms === false ? false : true,