7b4a051a1f
margin 後備(供缺 OpenType halt 之字型): - jiya.halfWidth: "halt"(預設)|"margin"。margin 以 width:0.5em+字身依墨色 偏側溢出定位,於 CSS 盒模型重現 halt 之半形 advance(真 0.5em;相鄰標點各 0.5em、合佔 1em,無負 margin 之鄰接疊加/單側重疊)。模式由 data-jz-halfwidth 子樹屬性決定(可逐區塊/逐 lang,含 halt-island 反置)。 - 偏側 inkBias 依字身墨色中心給 left/center/right/full;參考表據方正書宋 GBK 實測,consumer 可經 jiya.bias 逐 lang 逐字覆寫。 - _lang.css 字型堆疊僅作後備(全包 :where 零特異度、只命中帶 lang 屬性之元素、 不直接覆寫 jz-inner)→ 消費端 font-family 恆優先,標點隨之以消費端字型渲染。 - 新增 tools/measure-bias.py(量 glyph ink 中心、產偏側建議表)+ README 「字型適配工作流」。demo/fallback.html:方正書宋 GBK 對照 halt 失效 vs margin。 下游回饋修復: - 1a:adjacentLogicalChar 透明穿越 jz-jinze(同 jz-hws/樣式行內)→ pill 緊鄰 CJK 標點時,左緣間隙與作者空格剝除復原(jinze 先於 spacing 之交互)。 - 1b:CJK↔CJK 贅餘作者空格(含跨 inline 標籤)剝除、不留隙,與 CJK↔Latin 之 邊界正規化一致(DEL 哨符,全形空格 U+3000 不動)。 - 問題二:新增 justifyAtoms 選項;false → jz-char/jz-jinze 改 display:inline, 相容分頁器(Paged.js)對齊引擎(halt 半形與禁則 nowrap 保留)。 測試 43→49 全通過;dist 重建;README/ARCHITECTURE 同步更新契約。
142 lines
4.8 KiB
TypeScript
142 lines
4.8 KiB
TypeScript
import type { Finder } from "./core/finder.js";
|
||
import type { LangClass, LocaleConfig, PunctStyle } from "./core/locale.js";
|
||
import type { Bias, BiasTable } from "./core/unicode.js";
|
||
export type { LangClass, PunctStyle, Bias, BiasTable };
|
||
/** 長英文詞包裝設定。 */
|
||
export interface LongWordOptions {
|
||
minLength?: number;
|
||
lang?: string;
|
||
}
|
||
/** 標點擠壓設定(架構 §6.3)。布林 true 等同 { halfWidth: "halt" }。 */
|
||
export interface JiyaOptions {
|
||
/** 半形渲染機制:
|
||
* - "halt"(預設)— 用字型 OpenType `halt`,由字型按字形正確定位,需字型支援;
|
||
* - "margin" — 負 margin 後備模式,供缺 halt 之字型,依字形偏側表收半形。 */
|
||
halfWidth?: "halt" | "margin";
|
||
/** margin 後備模式之字形偏側覆寫表(逐 lang 逐字),覆寫內建參考預設。
|
||
* halt 模式不讀此欄。 */
|
||
bias?: BiasTable;
|
||
}
|
||
/** 分塊功能選擇:選擇器 → 該塊內生效之功能集(覆寫全域)。 */
|
||
export interface BlockRule {
|
||
selector: string;
|
||
features: string[];
|
||
}
|
||
/** createJuzhen 之公開選項。所有欄位皆可選;預設見 normalizeOptions。 */
|
||
export interface JuzhenOptions {
|
||
/** 語言與全角/開明政策。 */
|
||
lang?: {
|
||
/** 無 lang 祖先時之預設語言標籤(預設 "zh-Hant")。 */
|
||
default?: string;
|
||
/** 全域標點擠壓預設:quanjiao(全角式)|kaiming(開明式)|
|
||
* banjiao(半角式)。覆寫內建逐語言預設,可被 policy 逐 lang 覆寫。 */
|
||
style?: PunctStyle;
|
||
/** 逐 lang 覆寫(最高優先)。 */
|
||
policy?: Partial<Record<LangClass, PunctStyle>>;
|
||
};
|
||
/** 間隙標記沿用之 class(v1 相容;預設無額外 class)。 */
|
||
autospaceClass?: string;
|
||
/** justify 原子化:jz-char/jz-jinze 是否以 inline-block 作對齊單一原子
|
||
* (預設 true)。設 false 改 display:inline——用於分頁器(如 Paged.js)之
|
||
* 對齊引擎會把每個 inline-block 邊界當伸縮點、與 CJK inter-ideograph 疊加
|
||
* 致窄欄散架之情形(halt 半形與 jinze nowrap 仍保留)。 */
|
||
justifyAtoms?: boolean;
|
||
/** 作用域限定(§3.6)。 */
|
||
scope?: {
|
||
root?: Element | string;
|
||
include?: string | null;
|
||
avoid?: string;
|
||
};
|
||
spacing?: boolean;
|
||
longWord?: boolean | LongWordOptions;
|
||
jiya?: boolean | JiyaOptions;
|
||
jinze?: boolean;
|
||
hanging?: boolean;
|
||
biaodian?: boolean;
|
||
emphasis?: boolean;
|
||
ruby?: boolean;
|
||
/** 分塊功能選擇(§3.6)。 */
|
||
blocks?: BlockRule[];
|
||
styleInlines?: string[];
|
||
blockTags?: string[];
|
||
skipTags?: string[];
|
||
pillSelector?: string;
|
||
skipAttribute?: string;
|
||
isSkipped?: (node: Node) => boolean;
|
||
}
|
||
/** 正規化後之內部選項。 */
|
||
export interface ResolvedOptions {
|
||
locale: LocaleConfig;
|
||
autospaceClass: string;
|
||
justifyAtoms: boolean;
|
||
scope: {
|
||
root: Element | string | null;
|
||
include: string | null;
|
||
avoid: string | null;
|
||
};
|
||
features: {
|
||
spacing: boolean;
|
||
longWord: boolean;
|
||
jiya: boolean;
|
||
jinze: boolean;
|
||
hanging: boolean;
|
||
biaodian: boolean;
|
||
emphasis: boolean;
|
||
ruby: boolean;
|
||
};
|
||
longWord: {
|
||
minLength: number;
|
||
lang: string;
|
||
};
|
||
/** 擠壓半形渲染設定(halt 預設/margin 後備)。 */
|
||
jiyaConfig: {
|
||
halfWidth: "halt" | "margin";
|
||
bias: BiasTable;
|
||
};
|
||
blocks: BlockRule[];
|
||
finder: {
|
||
styleInlines: Set<string>;
|
||
blockTags: Set<string>;
|
||
skipTags: Set<string>;
|
||
pillSelector: string;
|
||
skipAttribute: string | null;
|
||
isSkipped: ((node: Node) => boolean) | null;
|
||
};
|
||
}
|
||
/** render/revert 之統一上下文(§3.3)。 */
|
||
export interface RenderContext {
|
||
root: Element;
|
||
options: ResolvedOptions;
|
||
finder: Finder;
|
||
}
|
||
/**
|
||
* charify 階段之包裝請求:把 node.data[start, end) 包進 build() 造出之元素。
|
||
* 同階段各 pass 之請求須互不重疊(標點/字母段天然不交集)。
|
||
*/
|
||
export interface WrapRequest {
|
||
start: number;
|
||
end: number;
|
||
build: (text: string) => HTMLElement;
|
||
pass: string;
|
||
}
|
||
/** pass 種類。 */
|
||
export type PassKind = "charify" | "standalone";
|
||
interface BasePass {
|
||
name: string;
|
||
order: number;
|
||
kind: PassKind;
|
||
enabled: (options: ResolvedOptions) => boolean;
|
||
revert: (ctx: RenderContext) => void;
|
||
}
|
||
/** 共享 P1 走訪之字元包裝 pass。 */
|
||
export interface CharifyPass extends BasePass {
|
||
kind: "charify";
|
||
collect: (node: Text, ctx: RenderContext) => WrapRequest[];
|
||
}
|
||
/** 自跑走訪/版面後處理之 pass。 */
|
||
export interface StandalonePass extends BasePass {
|
||
kind: "standalone";
|
||
render: (ctx: RenderContext) => void;
|
||
}
|
||
export type Pass = CharifyPass | StandalonePass;
|