diff --git a/examples/tests/text-vertical-align.ts b/examples/tests/text-vertical-align.ts index 9b75eb8..16787f3 100644 --- a/examples/tests/text-vertical-align.ts +++ b/examples/tests/text-vertical-align.ts @@ -7,6 +7,7 @@ import type { ExampleSettings } from '../common/ExampleSettings.js'; import { paginateTestRows, type TestRow } from '../common/paginateTestRows.js'; import { PageContainer } from '../common/PageContainer.js'; import { constructTestRow } from '../common/constructTestRow.js'; +import { waitForLoadedDimensions } from '../common/utils.js'; export async function automation(settings: ExampleSettings) { // Snapshot all the pages @@ -201,5 +202,42 @@ function generateVerticalAlignTest( ); }, }, + { + title: `Explicit h, no maxHeight ('verticalAlign', ${textRenderer}, fontSize = 50, lineHeight = 70)`, + content: async (rowNode) => { + const baseProps = { + ...NODE_PROPS, + text: 'txyz', + textRendererOverride: textRenderer, + forceLoad: true, + } satisfies Partial; + + const makeBoxedTextNode = async ( + verticalAlign: 'top' | 'middle' | 'bottom', + ) => { + const node = renderer.createTextNode({ + ...baseProps, + verticalAlign, + parent: rowNode, + }); + await waitForLoadedDimensions(node); + node.h = CONTAINER_SIZE; + return node; + }; + + const middleNode = await makeBoxedTextNode('middle'); + const topNode = await makeBoxedTextNode('top'); + const bottomNode = await makeBoxedTextNode('bottom'); + + return await constructTestRow({ renderer, rowNode }, [ + 'verticalAlign: middle\n(node.h, no maxHeight)\n->', + getSquare(renderer, middleNode), + 'top ->', + getSquare(renderer, topNode), + 'bottom ->', + getSquare(renderer, bottomNode), + ]); + }, + }, ] satisfies TestRow[]; } diff --git a/src/core/CoreTextNode.ts b/src/core/CoreTextNode.ts index ae36a6a..0fe5b2d 100644 --- a/src/core/CoreTextNode.ts +++ b/src/core/CoreTextNode.ts @@ -149,11 +149,14 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { } } - if (hasMaxHeight === true) { + const intrinsicH = this._renderInfo.height; + const boxH = hasMaxHeight === true ? maxHeight : h; + const slackY = boxH - intrinsicH; + if (slackY > 0) { if (verticalAlign === 'bottom') { - containY = maxHeight - h; + containY = slackY; } else if (verticalAlign === 'middle') { - containY = (maxHeight - h) * 0.5; + containY = slackY * 0.5; } } diff --git a/src/core/text-rendering/TextRenderer.ts b/src/core/text-rendering/TextRenderer.ts index 20a1432..677ad94 100644 --- a/src/core/text-rendering/TextRenderer.ts +++ b/src/core/text-rendering/TextRenderer.ts @@ -231,10 +231,13 @@ export interface TrProps extends TrFontProps { */ maxLines: number; /** - * Vertical alignment of the text block within `maxHeight`. + * Vertical alignment of the text block within its containing box. * * @remarks - * Activates when `maxHeight > 0`. Composes with `textBaselineMode` + * The containing box is `maxHeight` if set, otherwise the node's + * own `h` (which a flex parent or the user may have grown beyond + * the intrinsic text height). Activates whenever the box is taller + * than the intrinsic text height. Composes with `textBaselineMode` * (per-line anchor). CSS line-box semantics — `'top'` leaves * half-leading above the first line's cap-top; `'bottom'` leaves * half-leading below the last line's descender. diff --git a/visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png b/visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png index 483cef8..303ef3a 100644 Binary files a/visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png and b/visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png differ diff --git a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png index 51d991a..583ea58 100644 Binary files a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png and b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png differ diff --git a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png index 93c1064..d3ed8f0 100644 Binary files a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png and b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png differ diff --git a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-3.png b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-3.png new file mode 100644 index 0000000..a74b891 Binary files /dev/null and b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-3.png differ diff --git a/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-4.png b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-4.png new file mode 100644 index 0000000..0e38aee Binary files /dev/null and b/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-4.png differ