@unmade/text-renderer 1.1.1 → 1.3.0
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/README.md +231 -0
- package/dist/{__vite-browser-external-CijFC1_R.js → __vite-browser-external-oLchLuMx.js} +1 -1
- package/dist/baselines/index.d.ts +19 -0
- package/dist/ce-adapter/index.cjs +1 -1
- package/dist/ce-adapter/index.js +1 -1
- package/dist/fitting/index.d.ts +86 -0
- package/dist/helpers/bbox.d.ts +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1143 -339
- package/dist/layout/index.d.ts +77 -0
- package/dist/node/baselines/index.d.ts +19 -0
- package/dist/node/fitting/index.d.ts +86 -0
- package/dist/node/helpers/bbox.d.ts +2 -1
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.js +446 -201
- package/dist/node/layout/index.d.ts +77 -0
- package/dist/node/renderText.d.ts +3 -0
- package/dist/node/rendering/index.d.ts +2 -2
- package/dist/node/types.d.ts +3 -0
- package/dist/renderText.d.ts +3 -0
- package/dist/rendering/index.d.ts +2 -2
- package/dist/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
- package/dist/types.d.ts +3 -0
- package/dist/worker/baselines/index.d.ts +19 -0
- package/dist/worker/fitting/index.d.ts +86 -0
- package/dist/worker/helpers/bbox.d.ts +2 -1
- package/dist/worker/index.d.ts +2 -0
- package/dist/worker/index.js +2846 -2377
- package/dist/worker/layout/index.d.ts +77 -0
- package/dist/worker/renderText.d.ts +3 -0
- package/dist/worker/rendering/index.d.ts +2 -2
- package/dist/worker/types.d.ts +3 -0
- package/package.json +12 -5
- package/dist/helpers/matrix.d.ts +0 -8
- package/dist/node/helpers/matrix.d.ts +0 -8
- package/dist/worker/helpers/matrix.d.ts +0 -8
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { LoadedFont } from '../loading';
|
|
2
|
+
import { PathEntry } from '../rendering';
|
|
3
|
+
import { BaselineConfig, BaselineType, BoxDimensions, ColourMap, HorizontalTextAlignmentValues, MeasurementUnits, PhysicalSize, TextSpacing, VerticalTextAlignmentValues } from '../types';
|
|
4
|
+
export interface LayoutTextOptions {
|
|
5
|
+
font: LoadedFont;
|
|
6
|
+
text: string;
|
|
7
|
+
boxDimensions: BoxDimensions;
|
|
8
|
+
physicalSize: PhysicalSize;
|
|
9
|
+
/** When provided, bypasses the physicalSize → font size calculation. */
|
|
10
|
+
fontSize?: number;
|
|
11
|
+
spacing?: TextSpacing;
|
|
12
|
+
baseline?: BaselineType | BaselineConfig;
|
|
13
|
+
horizontalAlignment?: HorizontalTextAlignmentValues;
|
|
14
|
+
verticalAlignment?: VerticalTextAlignmentValues;
|
|
15
|
+
colourMap?: ColourMap;
|
|
16
|
+
}
|
|
17
|
+
export interface TextLayout {
|
|
18
|
+
fontSize: number;
|
|
19
|
+
/** Lines as laid out — curved and custom baselines collapse to one. */
|
|
20
|
+
lines: string[];
|
|
21
|
+
/** Every glyph, positioned. Rendering draws these; measuring bounds them. */
|
|
22
|
+
paths: PathEntry[];
|
|
23
|
+
spacing: TextSpacing;
|
|
24
|
+
tallestHeight: number;
|
|
25
|
+
totalHeight: number;
|
|
26
|
+
maxBaseline: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Position every glyph of `text` within `boxDimensions`.
|
|
30
|
+
*
|
|
31
|
+
* Shared by rendering and measuring so the two cannot disagree: what gets
|
|
32
|
+
* measured is the same set of positioned glyphs that gets drawn. The
|
|
33
|
+
* configuration engine has two independent measurement paths that have drifted
|
|
34
|
+
* apart over time, which is the outcome this exists to prevent.
|
|
35
|
+
*/
|
|
36
|
+
export declare const layoutText: (options: LayoutTextOptions) => TextLayout;
|
|
37
|
+
export interface MeasuredLine {
|
|
38
|
+
text: string;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
baseline: number;
|
|
42
|
+
}
|
|
43
|
+
export interface TextMeasurement {
|
|
44
|
+
fontSize: number;
|
|
45
|
+
/** Bounds of the drawn glyphs, in the box's pixel coordinates. */
|
|
46
|
+
bbox: {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
width: number;
|
|
50
|
+
height: number;
|
|
51
|
+
};
|
|
52
|
+
physicalWidth: number;
|
|
53
|
+
physicalHeight: number;
|
|
54
|
+
physicalUnits: MeasurementUnits;
|
|
55
|
+
/**
|
|
56
|
+
* Physical height of a standard capital at this font size — the cap height.
|
|
57
|
+
*
|
|
58
|
+
* Not derivable from `physicalHeight`: that measures the glyphs actually
|
|
59
|
+
* present, so it moves with descenders and accents, whereas cap height is a
|
|
60
|
+
* property of the font and size alone. It is persisted with the design and
|
|
61
|
+
* reaches the factory, so it has to be reported rather than inferred.
|
|
62
|
+
*/
|
|
63
|
+
physicalCapHeight: number;
|
|
64
|
+
lines: MeasuredLine[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Measure text as it would be drawn.
|
|
68
|
+
*
|
|
69
|
+
* Bounds the same positioned glyphs `renderText` draws, rather than
|
|
70
|
+
* re-deriving dimensions from font metrics — so a measurement can't disagree
|
|
71
|
+
* with the artwork it describes. In particular a curved line's bounds follow
|
|
72
|
+
* the arch, which a flat metrics calculation cannot know about.
|
|
73
|
+
*
|
|
74
|
+
* Throws where `renderText` would throw, for the same reasons. If this
|
|
75
|
+
* succeeds, rendering the same options will too.
|
|
76
|
+
*/
|
|
77
|
+
export declare const measureText: (options: LayoutTextOptions) => TextMeasurement;
|
|
@@ -28,6 +28,25 @@ export interface GenerateCurvedBaselineOptions {
|
|
|
28
28
|
textHeight: number;
|
|
29
29
|
verticalAlignment: VerticalTextAlignmentValues;
|
|
30
30
|
}
|
|
31
|
+
/** Where the arch sits vertically: its peak, and the baseline at its ends. */
|
|
32
|
+
export interface CurvedBaselineGeometry {
|
|
33
|
+
/** y of the peak — the highest point of the baseline. */
|
|
34
|
+
curveTop: number;
|
|
35
|
+
/** y of the two ends — the lowest points of the baseline. */
|
|
36
|
+
curveBottom: number;
|
|
37
|
+
/** Horizontal gap left at each end so the outer glyphs are not clipped. */
|
|
38
|
+
curveXInset: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The arch's placement, on its own so that the path and anything reasoning
|
|
42
|
+
* about where the text will land come from one calculation.
|
|
43
|
+
*
|
|
44
|
+
* Sizing needs this: it has to know where the renderer will actually put the
|
|
45
|
+
* baseline before it can say whether the text riding it clears the box. Working
|
|
46
|
+
* that out separately is what let the fit engine believe a size fitted while
|
|
47
|
+
* the render clipped.
|
|
48
|
+
*/
|
|
49
|
+
export declare const curvedBaselineGeometry: ({ boxDimensions, baseline, textHeight, verticalAlignment, }: GenerateCurvedBaselineOptions) => CurvedBaselineGeometry;
|
|
31
50
|
/**
|
|
32
51
|
* Generate a path command to curve text and align that text to the top of the box.
|
|
33
52
|
* Uses two quadratic bezier curves — one from the bottom left to the peak, and a
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { LoadedFont } from '../loading';
|
|
2
|
+
import { BaselineConfig, BaselineType, BoxDimensions, PhysicalSize, TextSpacing, VerticalTextAlignmentValues } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* How the font size is arrived at.
|
|
5
|
+
*
|
|
6
|
+
* `fitToBox` solves for the largest size the box allows. The other two pin the
|
|
7
|
+
* size and leave the text length as the free variable instead — which is what a
|
|
8
|
+
* fixed size preset is: hold 60mm, and fit as many characters as will go. All
|
|
9
|
+
* three then behave identically downstream, so a pinned size is an ordinary mode
|
|
10
|
+
* rather than a special path.
|
|
11
|
+
*/
|
|
12
|
+
export type FitSize = {
|
|
13
|
+
mode: 'fitToBox';
|
|
14
|
+
minFontSize: number;
|
|
15
|
+
maxFontSize: number;
|
|
16
|
+
} | {
|
|
17
|
+
mode: 'fontSize';
|
|
18
|
+
fontSize: number;
|
|
19
|
+
} | {
|
|
20
|
+
mode: 'physicalSize';
|
|
21
|
+
physicalSize: PhysicalSize;
|
|
22
|
+
};
|
|
23
|
+
export interface FitTextToBoxOptions {
|
|
24
|
+
font: LoadedFont;
|
|
25
|
+
text: string;
|
|
26
|
+
boxDimensions: BoxDimensions;
|
|
27
|
+
size: FitSize;
|
|
28
|
+
spacing?: TextSpacing;
|
|
29
|
+
baseline?: BaselineType | BaselineConfig;
|
|
30
|
+
verticalAlignment?: VerticalTextAlignmentValues;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Which limit decided the outcome.
|
|
34
|
+
*
|
|
35
|
+
* - `width` — the box width, or the arc/custom path length for a non-flat baseline
|
|
36
|
+
* - `height` — the box height
|
|
37
|
+
* - `requestedSize` — the size the caller asked for, reached before the box
|
|
38
|
+
* mattered. Covers both hitting `maxFontSize` when solving and simply getting
|
|
39
|
+
* the pinned size that was requested.
|
|
40
|
+
*/
|
|
41
|
+
export type FitConstraint = 'width' | 'height' | 'requestedSize';
|
|
42
|
+
export interface FitTextToBoxResult {
|
|
43
|
+
fontSize: number;
|
|
44
|
+
/** False when the text cannot fit within the box even at minFontSize. */
|
|
45
|
+
fits: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* When `fits`, the limit that capped the size. When not, the limit that could
|
|
48
|
+
* not be satisfied.
|
|
49
|
+
*
|
|
50
|
+
* Callers need this to tell one failure from another: overflowing the width
|
|
51
|
+
* and overflowing the height call for different responses, and in the
|
|
52
|
+
* configuration engine they surface as different messages to the user.
|
|
53
|
+
*/
|
|
54
|
+
boundBy: FitConstraint;
|
|
55
|
+
}
|
|
56
|
+
export interface FitAndTruncateTextToBoxResult extends FitTextToBoxResult {
|
|
57
|
+
text: string;
|
|
58
|
+
truncated: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* How the text was shortened. Reported separately because dropping a line and
|
|
61
|
+
* trimming characters are different outcomes with different messages, and a
|
|
62
|
+
* single pass can do both — drop a line, then still need to trim.
|
|
63
|
+
*/
|
|
64
|
+
linesDropped: number;
|
|
65
|
+
charactersRemoved: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Calculate the font size at which `text` fills `boxDimensions` as closely
|
|
69
|
+
* as possible without overflowing, for any baseline shape. This replaces
|
|
70
|
+
* binary-searching for a fitting font size: flat and custom baselines are
|
|
71
|
+
* solved in one step, from a single measurement, while curved baselines need
|
|
72
|
+
* a bounded numeric solve (see solveCurvedFit).
|
|
73
|
+
*
|
|
74
|
+
* `fits: false` means the text doesn't fit even at minFontSize — the caller
|
|
75
|
+
* (e.g. fitAndTruncateTextToBox) should either shorten the text or accept
|
|
76
|
+
* the overflow at minFontSize.
|
|
77
|
+
*/
|
|
78
|
+
export declare const getFontSizeToFitBox: (options: FitTextToBoxOptions) => FitTextToBoxResult;
|
|
79
|
+
/**
|
|
80
|
+
* Like getFontSizeToFitBox, but when text doesn't fit even at minFontSize,
|
|
81
|
+
* shortens it (dropping the last whole line first if there is more than
|
|
82
|
+
* one, otherwise trimming trailing characters) and retries until it fits
|
|
83
|
+
* or there's nothing left to remove. Mirrors CE's existing truncation UX —
|
|
84
|
+
* text lost this way is a caller/product concern, not a rendering one.
|
|
85
|
+
*/
|
|
86
|
+
export declare const fitAndTruncateTextToBox: (options: FitTextToBoxOptions) => FitAndTruncateTextToBoxResult;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PlatformMatrix } from '../types';
|
|
1
2
|
export declare class Box {
|
|
2
3
|
corners: DOMPoint[];
|
|
3
4
|
x1: number;
|
|
@@ -13,7 +14,7 @@ export declare class Box {
|
|
|
13
14
|
get x4(): number;
|
|
14
15
|
get y4(): number;
|
|
15
16
|
constructor(x1: number, y1: number, x2: number, y2: number, x3?: number, y3?: number, x4?: number, y4?: number);
|
|
16
|
-
transform(matrix:
|
|
17
|
+
transform(matrix: PlatformMatrix): void;
|
|
17
18
|
toPointsArray(): number[][];
|
|
18
19
|
getBBox(): BBox;
|
|
19
20
|
}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { GetRenderedTextOptions } from './types';
|
|
2
2
|
export { type GenerateCurvedBaselineOptions, type GenerateFlatBaselineOptions, generateCurvedBaseline, generateFlatBaseline, normaliseBaselineOption, validateCustomBaselinePath, } from './baselines';
|
|
3
3
|
export { DEFAULT_OUTLINE_FACTOR, DEFAULT_SPACING, LINE_HEIGHT, } from './constants';
|
|
4
|
+
export { type FitAndTruncateTextToBoxResult, type FitConstraint, type FitSize, type FitTextToBoxOptions, type FitTextToBoxResult, fitAndTruncateTextToBox, getFontSizeToFitBox, } from './fitting';
|
|
4
5
|
export { getFontColours } from './glyph/svg-glyph-converter';
|
|
6
|
+
export { type LayoutTextOptions, layoutText, type MeasuredLine, measureText, type TextLayout, type TextMeasurement, } from './layout';
|
|
5
7
|
export { getFontCache, type LoadedFont, loadFont } from './loading';
|
|
6
8
|
export { type GetFontSizeFromPhysicalSizeOptions, type GetTextMetricsAtFontSizeOptions, getFontSizeFromPhysicalSize, getTextMetricsAtFontSize, } from './measuring';
|
|
7
9
|
export type { GetTextAsPathDataOptions, SvgGlyphEntry } from './rendering';
|