@vyaz/core 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.js +155 -22
- package/dist/index.d.ts +46 -2
- package/dist/index.js +1747 -5
- package/dist/measure/FontMetricsProvider.d.ts +39 -17
- package/package.json +1 -1
package/dist/index.browser.js
CHANGED
|
@@ -18200,21 +18200,55 @@ function normaliseWeight(weight) {
|
|
|
18200
18200
|
return mapped;
|
|
18201
18201
|
return weight;
|
|
18202
18202
|
}
|
|
18203
|
-
function
|
|
18204
|
-
|
|
18203
|
+
function weightToNumber(weight) {
|
|
18204
|
+
const num = parseInt(weight, 10);
|
|
18205
|
+
return isNaN(num) ? 400 : num;
|
|
18206
|
+
}
|
|
18207
|
+
function variantKey(weight, style) {
|
|
18208
|
+
return `${normaliseWeight(weight)}_${style}`;
|
|
18209
|
+
}
|
|
18210
|
+
function nearestWeight(registeredWeights, requested) {
|
|
18211
|
+
if (registeredWeights.length === 0)
|
|
18212
|
+
return null;
|
|
18213
|
+
let best = registeredWeights[0];
|
|
18214
|
+
let bestDist = Math.abs(best - requested);
|
|
18215
|
+
for (let i = 1;i < registeredWeights.length; i++) {
|
|
18216
|
+
const w = registeredWeights[i];
|
|
18217
|
+
const dist = Math.abs(w - requested);
|
|
18218
|
+
if (dist < bestDist || dist === bestDist && w > best) {
|
|
18219
|
+
best = w;
|
|
18220
|
+
bestDist = dist;
|
|
18221
|
+
}
|
|
18222
|
+
}
|
|
18223
|
+
return best;
|
|
18205
18224
|
}
|
|
18206
18225
|
|
|
18207
18226
|
class FontMetricsProvider {
|
|
18208
|
-
|
|
18227
|
+
registry = new Map;
|
|
18209
18228
|
metricsCache = new Map;
|
|
18210
18229
|
mode = "browser";
|
|
18230
|
+
pendingRegistrations = new Set;
|
|
18231
|
+
_measureCanvas = null;
|
|
18232
|
+
_measureCtx = null;
|
|
18233
|
+
_getMeasureContext() {
|
|
18234
|
+
if (!this._measureCtx) {
|
|
18235
|
+
if (typeof OffscreenCanvas !== "undefined") {
|
|
18236
|
+
this._measureCanvas = new OffscreenCanvas(1, 1);
|
|
18237
|
+
this._measureCtx = this._measureCanvas.getContext("2d");
|
|
18238
|
+
} else {
|
|
18239
|
+
this._measureCanvas = document.createElement("canvas");
|
|
18240
|
+
this._measureCtx = this._measureCanvas.getContext("2d");
|
|
18241
|
+
}
|
|
18242
|
+
}
|
|
18243
|
+
return this._measureCtx;
|
|
18244
|
+
}
|
|
18211
18245
|
setMode(mode) {
|
|
18212
18246
|
if (this.mode === mode)
|
|
18213
18247
|
return;
|
|
18214
18248
|
this.mode = mode;
|
|
18215
18249
|
this.metricsCache.clear();
|
|
18216
18250
|
if (mode === "office") {
|
|
18217
|
-
enableOfficeTextMeasure(this.
|
|
18251
|
+
enableOfficeTextMeasure(this._flattenCache());
|
|
18218
18252
|
} else {
|
|
18219
18253
|
disableOfficeTextMeasure();
|
|
18220
18254
|
}
|
|
@@ -18222,7 +18256,25 @@ class FontMetricsProvider {
|
|
|
18222
18256
|
getMode() {
|
|
18223
18257
|
return this.mode;
|
|
18224
18258
|
}
|
|
18259
|
+
_flattenCache() {
|
|
18260
|
+
const flat = new Map;
|
|
18261
|
+
for (const [family, variants] of this.registry) {
|
|
18262
|
+
for (const [vKey, font] of variants) {
|
|
18263
|
+
flat.set(`${family}_${vKey}`, font);
|
|
18264
|
+
}
|
|
18265
|
+
}
|
|
18266
|
+
return flat;
|
|
18267
|
+
}
|
|
18225
18268
|
async registerFont(family, options, source, sourcePath) {
|
|
18269
|
+
const promise = this._registerFontInternal(family, options, source, sourcePath);
|
|
18270
|
+
this.pendingRegistrations.add(promise);
|
|
18271
|
+
try {
|
|
18272
|
+
await promise;
|
|
18273
|
+
} finally {
|
|
18274
|
+
this.pendingRegistrations.delete(promise);
|
|
18275
|
+
}
|
|
18276
|
+
}
|
|
18277
|
+
async _registerFontInternal(family, options, source, sourcePath) {
|
|
18226
18278
|
const { createFontFace: createFontFace2 } = await Promise.resolve().then(() => exports_FontEngine);
|
|
18227
18279
|
const { registerCanvasFont: registerCanvasFont2 } = await init_canvas_polyfill().then(() => exports_canvas_polyfill);
|
|
18228
18280
|
if (typeof source === "string") {
|
|
@@ -18230,25 +18282,107 @@ class FontMetricsProvider {
|
|
|
18230
18282
|
source = await getFontBuffer2(source);
|
|
18231
18283
|
}
|
|
18232
18284
|
const font = await createFontFace2(source);
|
|
18233
|
-
const
|
|
18234
|
-
|
|
18235
|
-
|
|
18285
|
+
const w = options.weight || "normal";
|
|
18286
|
+
const s = options.style || "normal";
|
|
18287
|
+
const vKey = variantKey(w, s);
|
|
18288
|
+
if (!this.registry.has(family)) {
|
|
18289
|
+
this.registry.set(family, new Map);
|
|
18290
|
+
}
|
|
18291
|
+
this.registry.get(family).set(vKey, font);
|
|
18292
|
+
for (const key of this.metricsCache.keys()) {
|
|
18293
|
+
if (key.startsWith(family)) {
|
|
18294
|
+
this.metricsCache.delete(key);
|
|
18295
|
+
}
|
|
18296
|
+
}
|
|
18236
18297
|
if (sourcePath) {
|
|
18237
18298
|
registerCanvasFont2(sourcePath, family);
|
|
18238
18299
|
}
|
|
18239
18300
|
}
|
|
18301
|
+
async waitForPendingRegistrations() {
|
|
18302
|
+
await Promise.all(this.pendingRegistrations);
|
|
18303
|
+
}
|
|
18304
|
+
getRegisteredFamilies() {
|
|
18305
|
+
return Array.from(this.registry.keys());
|
|
18306
|
+
}
|
|
18307
|
+
getFamilyVariants(family) {
|
|
18308
|
+
const variants = this.registry.get(family);
|
|
18309
|
+
return variants ? Array.from(variants.keys()) : [];
|
|
18310
|
+
}
|
|
18240
18311
|
getFont(family, weight = "normal", style = "normal") {
|
|
18241
|
-
const
|
|
18242
|
-
|
|
18312
|
+
const resolved = this._resolveFont(family, weight, style);
|
|
18313
|
+
if (!resolved)
|
|
18314
|
+
return;
|
|
18315
|
+
return resolved.font;
|
|
18316
|
+
}
|
|
18317
|
+
_resolveFont(family, weight, style) {
|
|
18318
|
+
const variants = this.registry.get(family);
|
|
18319
|
+
if (!variants || variants.size === 0)
|
|
18320
|
+
return null;
|
|
18321
|
+
const normalisedW = normaliseWeight(weight);
|
|
18322
|
+
const normalisedS = style;
|
|
18323
|
+
let key = variantKey(normalisedW, normalisedS);
|
|
18324
|
+
let font = variants.get(key);
|
|
18325
|
+
if (font)
|
|
18326
|
+
return { font, resolvedWeight: normalisedW, resolvedStyle: normalisedS };
|
|
18327
|
+
if (normalisedS === "italic") {
|
|
18328
|
+
key = variantKey(normalisedW, "normal");
|
|
18329
|
+
font = variants.get(key);
|
|
18330
|
+
if (font)
|
|
18331
|
+
return { font, resolvedWeight: normalisedW, resolvedStyle: "normal" };
|
|
18332
|
+
}
|
|
18333
|
+
const sameStyleWeights = [];
|
|
18334
|
+
for (const vKey of variants.keys()) {
|
|
18335
|
+
const [_w, _s] = vKey.split("_");
|
|
18336
|
+
if (_s === normalisedS) {
|
|
18337
|
+
sameStyleWeights.push(weightToNumber(_w));
|
|
18338
|
+
}
|
|
18339
|
+
}
|
|
18340
|
+
const sameStyleNearest = nearestWeight(sameStyleWeights, weightToNumber(normalisedW));
|
|
18341
|
+
if (sameStyleNearest !== null) {
|
|
18342
|
+
key = variantKey(String(sameStyleNearest), normalisedS);
|
|
18343
|
+
font = variants.get(key);
|
|
18344
|
+
if (font)
|
|
18345
|
+
return { font, resolvedWeight: String(sameStyleNearest), resolvedStyle: normalisedS };
|
|
18346
|
+
}
|
|
18347
|
+
if (normalisedS === "italic") {
|
|
18348
|
+
const normalWeights = [];
|
|
18349
|
+
for (const vKey of variants.keys()) {
|
|
18350
|
+
const [_w, _s] = vKey.split("_");
|
|
18351
|
+
if (_s === "normal") {
|
|
18352
|
+
normalWeights.push(weightToNumber(_w));
|
|
18353
|
+
}
|
|
18354
|
+
}
|
|
18355
|
+
const normalNearest = nearestWeight(normalWeights, weightToNumber(normalisedW));
|
|
18356
|
+
if (normalNearest !== null) {
|
|
18357
|
+
key = variantKey(String(normalNearest), "normal");
|
|
18358
|
+
font = variants.get(key);
|
|
18359
|
+
if (font)
|
|
18360
|
+
return { font, resolvedWeight: String(normalNearest), resolvedStyle: "normal" };
|
|
18361
|
+
}
|
|
18362
|
+
}
|
|
18363
|
+
const firstKey = variants.keys().next().value;
|
|
18364
|
+
if (firstKey) {
|
|
18365
|
+
font = variants.get(firstKey);
|
|
18366
|
+
if (font) {
|
|
18367
|
+
const [_w, _s] = firstKey.split("_");
|
|
18368
|
+
return { font, resolvedWeight: _w, resolvedStyle: _s };
|
|
18369
|
+
}
|
|
18370
|
+
}
|
|
18371
|
+
return null;
|
|
18243
18372
|
}
|
|
18244
18373
|
getMetrics(fontFamily, fontSize, weight = "normal", style = "normal") {
|
|
18245
|
-
const
|
|
18246
|
-
|
|
18374
|
+
const _process2 = typeof globalThis !== "undefined" ? globalThis.process : undefined;
|
|
18375
|
+
if (this.pendingRegistrations.size > 0 && _process2?.env?.NODE_ENV !== "production") {
|
|
18376
|
+
console.warn("[vyaz] getMetrics() called while registerFont() promises are still pending. Wait for registerFont() to resolve before layout to avoid inaccurate metrics. Use fontMetricsProvider.waitForPendingRegistrations() if needed.");
|
|
18377
|
+
}
|
|
18378
|
+
const normalisedW = normaliseWeight(weight);
|
|
18379
|
+
const metricsKey = `${fontFamily}_${normalisedW}_${style}_${fontSize}_${this.mode}`;
|
|
18247
18380
|
const cached = this.metricsCache.get(metricsKey);
|
|
18248
18381
|
if (cached)
|
|
18249
18382
|
return cached;
|
|
18250
|
-
const
|
|
18251
|
-
if (
|
|
18383
|
+
const resolved = this._resolveFont(fontFamily, weight, style);
|
|
18384
|
+
if (resolved) {
|
|
18385
|
+
const font = resolved.font;
|
|
18252
18386
|
const scale = fontSize / font.unitsPerEm;
|
|
18253
18387
|
let ascent;
|
|
18254
18388
|
let descent;
|
|
@@ -18272,13 +18406,12 @@ class FontMetricsProvider {
|
|
|
18272
18406
|
this.metricsCache.set(metricsKey, metrics);
|
|
18273
18407
|
return metrics;
|
|
18274
18408
|
}
|
|
18275
|
-
if (this.
|
|
18409
|
+
if (this.registry.has(fontFamily)) {
|
|
18276
18410
|
throw new FontNotFoundError(fontFamily, weight, style);
|
|
18277
18411
|
}
|
|
18278
18412
|
if (typeof document !== "undefined") {
|
|
18279
18413
|
try {
|
|
18280
|
-
const
|
|
18281
|
-
const ctx = canvas.getContext("2d");
|
|
18414
|
+
const ctx = this._getMeasureContext();
|
|
18282
18415
|
ctx.font = `${style} ${weight} ${fontSize}px ${fontFamily}`;
|
|
18283
18416
|
const m = ctx.measureText("M");
|
|
18284
18417
|
const metrics = {
|
|
@@ -24338,15 +24471,15 @@ function isLineStartCursor(cursor) {
|
|
|
24338
24471
|
return cursor.segmentIndex === 0 && cursor.graphemeIndex === 0;
|
|
24339
24472
|
}
|
|
24340
24473
|
function getCollapsedSpaceWidth(font, letterSpacing, cache) {
|
|
24341
|
-
const
|
|
24342
|
-
const cached = cache.get(
|
|
24474
|
+
const cacheKey2 = `${font}\x00${letterSpacing}`;
|
|
24475
|
+
const cached = cache.get(cacheKey2);
|
|
24343
24476
|
if (cached !== undefined)
|
|
24344
24477
|
return cached;
|
|
24345
24478
|
const options = letterSpacing === 0 ? undefined : { letterSpacing };
|
|
24346
24479
|
const joinedWidth = measureNaturalWidth(prepareWithSegments("A A", font, options));
|
|
24347
24480
|
const compactWidth = measureNaturalWidth(prepareWithSegments("AA", font, options));
|
|
24348
24481
|
const collapsedWidth = Math.max(0, joinedWidth - compactWidth);
|
|
24349
|
-
cache.set(
|
|
24482
|
+
cache.set(cacheKey2, collapsedWidth);
|
|
24350
24483
|
return collapsedWidth;
|
|
24351
24484
|
}
|
|
24352
24485
|
function prepareWholeItemLine(prepared) {
|
|
@@ -24591,11 +24724,11 @@ class ParagraphLayoutEngine {
|
|
|
24591
24724
|
layout(paragraph, maxWidth, yOffset = 0, fontProvider, listStyle, listIndex, listMarkerWidth) {
|
|
24592
24725
|
const provider = fontProvider || fontMetricsProvider;
|
|
24593
24726
|
const items = compileParagraph(paragraph);
|
|
24594
|
-
const
|
|
24595
|
-
let prepared = this.preparedCache.get(
|
|
24727
|
+
const cacheKey2 = JSON.stringify(paragraph);
|
|
24728
|
+
let prepared = this.preparedCache.get(cacheKey2);
|
|
24596
24729
|
if (!prepared) {
|
|
24597
24730
|
prepared = prepareRichInline(items);
|
|
24598
|
-
this.preparedCache.set(
|
|
24731
|
+
this.preparedCache.set(cacheKey2, prepared);
|
|
24599
24732
|
}
|
|
24600
24733
|
const effectiveMaxWidth = paragraph.style.whiteSpace === "nowrap" ? Infinity : maxWidth;
|
|
24601
24734
|
const pretextLines = [];
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,46 @@
|
|
|
5
5
|
* layout engines, font metric providers, renderers, and utilities.
|
|
6
6
|
*/
|
|
7
7
|
export type { TextFrame, Paragraph, ParagraphStyle, TextRun, InlineWidget, AutofitConfig, TextAlignment, WritingMode, TextOrientation, VerticalAlignment, ScriptType, WhiteSpace, MultiColumnConfig, DominantBaseline, LineFitEdge, TextAlignLast, WordBreak, LineBreak, OverflowWrap, TextDecorationStyle, TextTransform, ListType, NumberFormat, ListStylePosition, ListStyle, } from './types/Document.js';
|
|
8
|
-
export
|
|
8
|
+
export declare const DEFAULT_PARAGRAPH_STYLE: {
|
|
9
|
+
alignment: import("./index.js").TextAlignment;
|
|
10
|
+
lineHeight: number;
|
|
11
|
+
spaceBefore: number;
|
|
12
|
+
spaceAfter: number;
|
|
13
|
+
indent?: number;
|
|
14
|
+
leftIndent?: number;
|
|
15
|
+
rightIndent?: number;
|
|
16
|
+
textIndent?: number;
|
|
17
|
+
letterSpacing?: number;
|
|
18
|
+
textAlignLast?: import("./index.js").TextAlignLast;
|
|
19
|
+
wordBreak?: import("./index.js").WordBreak;
|
|
20
|
+
lineBreak?: import("./index.js").LineBreak;
|
|
21
|
+
overflowWrap?: import("./index.js").OverflowWrap;
|
|
22
|
+
hyphens?: boolean;
|
|
23
|
+
whiteSpace?: import("./index.js").WhiteSpace;
|
|
24
|
+
listStyle?: import("./index.js").ListStyle;
|
|
25
|
+
listRestart?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare const DEFAULT_TEXT_STYLE: {
|
|
28
|
+
type?: "text" | "inline-box" | undefined;
|
|
29
|
+
text?: string | undefined;
|
|
30
|
+
inlineWidget?: import("./index.js").InlineWidget | undefined;
|
|
31
|
+
fontFamily?: string | undefined;
|
|
32
|
+
fontSize?: number | undefined;
|
|
33
|
+
fontWeight?: number | "bold" | "normal" | undefined;
|
|
34
|
+
fontStyle?: "normal" | "italic" | undefined;
|
|
35
|
+
color?: string | undefined;
|
|
36
|
+
backgroundColor?: string | undefined;
|
|
37
|
+
letterSpacing?: number | undefined;
|
|
38
|
+
script?: import("./index.js").ScriptType | undefined;
|
|
39
|
+
underline?: boolean | undefined;
|
|
40
|
+
strikethrough?: boolean | undefined;
|
|
41
|
+
overline?: boolean | undefined;
|
|
42
|
+
textDecorationStyle?: import("./index.js").TextDecorationStyle | undefined;
|
|
43
|
+
textDecorationColor?: string | undefined;
|
|
44
|
+
textTransform?: import("./index.js").TextTransform | undefined;
|
|
45
|
+
fullWidth?: boolean | undefined;
|
|
46
|
+
fullSizeKana?: boolean | undefined;
|
|
47
|
+
};
|
|
9
48
|
export type { ParagraphLayoutResult, Line, Span, SpanFontMetrics, SemanticParagraph, SemanticLine, SemanticFragment, } from './types/LayoutTypes.js';
|
|
10
49
|
export type { FontMetrics, IFontMetricsProvider, GlyphData, } from './types/FontTypes.js';
|
|
11
50
|
export { ParagraphLayoutEngine, paragraphLayoutEngine } from './layout/ParagraphLayoutEngine.js';
|
|
@@ -19,7 +58,12 @@ export type { AutoFitOptions, AutoFitResult } from './layout/AutoFitEngine.js';
|
|
|
19
58
|
export { groupLinesByParagraph } from './utils/groupLinesByParagraph.js';
|
|
20
59
|
export type { ParagraphGroup } from './utils/groupLinesByParagraph.js';
|
|
21
60
|
export { transformText } from './utils/textTransform.js';
|
|
22
|
-
|
|
61
|
+
import { formatListNumber as _fln, defaultBulletChar as _dbc } from './utils/list.js';
|
|
62
|
+
export declare const formatListNumber: typeof _fln;
|
|
63
|
+
export declare const defaultBulletChar: typeof _dbc;
|
|
64
|
+
export declare const BULLET_CHARACTERS: {
|
|
65
|
+
[x: number]: string;
|
|
66
|
+
};
|
|
23
67
|
export { compileParagraph, getParagraphText, makeFontToken, splitParagraphByHardBreaks, collapseSegmentWhitespace } from './compile/DocumentCompiler.js';
|
|
24
68
|
export type { PreparedRichInlineItem } from './compile/DocumentCompiler.js';
|
|
25
69
|
export type { FontFace } from './measure/FontEngine.js';
|