Refactor/reacrhitecture to fsd+ #49
@@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Internal shape of pretext's PreparedTextWithSegments — only `segments` is in
|
||||||
|
* pretext's public TS type; the numeric arrays exist at runtime but are not in
|
||||||
|
* the published signature. Verified against node_modules/@chenglou/pretext/src/layout.ts.
|
||||||
|
*/
|
||||||
|
interface PretextInternals {
|
||||||
|
/**
|
||||||
|
* Per-segment text.
|
||||||
|
*/
|
||||||
|
segments: string[];
|
||||||
|
/**
|
||||||
|
* Per-segment full width in pixels.
|
||||||
|
*/
|
||||||
|
widths: number[];
|
||||||
|
/**
|
||||||
|
* Per-segment per-grapheme advance widths, or null when the segment is a single grapheme.
|
||||||
|
*/
|
||||||
|
breakableFitAdvances: (number[] | null)[];
|
||||||
|
/**
|
||||||
|
* Per-segment line-end fit advance.
|
||||||
|
*/
|
||||||
|
lineEndFitAdvances: number[];
|
||||||
|
/**
|
||||||
|
* Per-segment line-end paint advance.
|
||||||
|
*/
|
||||||
|
lineEndPaintAdvances: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-grapheme data computed during dual-font layout. Internal to the engine;
|
||||||
|
* consumed by computeLineRenderModel to derive the per-frame render model.
|
||||||
|
*/
|
||||||
|
export interface ComparisonChar {
|
||||||
|
/**
|
||||||
|
* Grapheme cluster (may be >1 code unit for emoji, combining marks).
|
||||||
|
*/
|
||||||
|
char: string;
|
||||||
|
/**
|
||||||
|
* X offset from line start in fontA, pixels.
|
||||||
|
*/
|
||||||
|
xA: number;
|
||||||
|
/**
|
||||||
|
* Advance width of this grapheme in fontA, pixels.
|
||||||
|
*/
|
||||||
|
widthA: number;
|
||||||
|
/**
|
||||||
|
* X offset from line start in fontB, pixels.
|
||||||
|
*/
|
||||||
|
xB: number;
|
||||||
|
/**
|
||||||
|
* Advance width of this grapheme in fontB, pixels.
|
||||||
|
*/
|
||||||
|
widthB: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single laid-out line. `chars` carries the per-grapheme data needed by
|
||||||
|
* computeLineRenderModel. Consumers should not iterate it directly.
|
||||||
|
*/
|
||||||
|
export interface ComparisonLine {
|
||||||
|
/**
|
||||||
|
* Full text of this line as returned by pretext.
|
||||||
|
*/
|
||||||
|
text: string;
|
||||||
|
/**
|
||||||
|
* Rendered width in pixels — maximum across fontA and fontB.
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
/**
|
||||||
|
* Per-grapheme metadata for both fonts.
|
||||||
|
*/
|
||||||
|
chars: ComparisonChar[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregated output of a dual-font layout pass.
|
||||||
|
*/
|
||||||
|
export interface ComparisonResult {
|
||||||
|
/**
|
||||||
|
* Per-line grapheme data. Empty when input text is empty.
|
||||||
|
*/
|
||||||
|
lines: ComparisonLine[];
|
||||||
|
/**
|
||||||
|
* Total height in pixels.
|
||||||
|
*/
|
||||||
|
totalHeight: number;
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import { describe } from 'vitest';
|
||||||
|
|
||||||
|
describe('computeLineRenderModel', () => {
|
||||||
|
// tests added in subsequent tasks
|
||||||
|
});
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import type {
|
||||||
|
ComparisonChar,
|
||||||
|
ComparisonLine,
|
||||||
|
} from '../DualFontLayout/DualFontLayout';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-line render slice consumed by Line.svelte. The window is centered on the
|
||||||
|
* slider's split index and clamps at line boundaries.
|
||||||
|
*/
|
||||||
|
export interface LineRenderModel {
|
||||||
|
/**
|
||||||
|
* Chars before the window joined into a single string, rendered as one fontA text run.
|
||||||
|
*/
|
||||||
|
leftText: string;
|
||||||
|
/**
|
||||||
|
* Window chars — each rendered as its own Character element with crossfade slots.
|
||||||
|
*/
|
||||||
|
windowChars: Array<{
|
||||||
|
/**
|
||||||
|
* Stable key for Svelte keyed each — survives slider movement within the same line.
|
||||||
|
*/
|
||||||
|
key: string;
|
||||||
|
/**
|
||||||
|
* Grapheme cluster to render.
|
||||||
|
*/
|
||||||
|
char: string;
|
||||||
|
/**
|
||||||
|
* True once the slider has crossed this char's threshold.
|
||||||
|
*/
|
||||||
|
isPast: boolean;
|
||||||
|
}>;
|
||||||
|
/**
|
||||||
|
* Chars after the window joined into a single string, rendered as one fontB text run.
|
||||||
|
*/
|
||||||
|
rightText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeLineRenderModel(
|
||||||
|
line: ComparisonLine,
|
||||||
|
sliderPos: number,
|
||||||
|
containerWidth: number,
|
||||||
|
windowSize: number,
|
||||||
|
): LineRenderModel {
|
||||||
|
throw new Error('not implemented');
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export type {
|
||||||
|
ComparisonLine,
|
||||||
|
ComparisonResult,
|
||||||
|
} from './DualFontLayout/DualFontLayout';
|
||||||
|
export {
|
||||||
|
computeLineRenderModel,
|
||||||
|
type LineRenderModel,
|
||||||
|
} from './computeLineRenderModel/computeLineRenderModel';
|
||||||
Reference in New Issue
Block a user