From b16d9543a88c0199b057f96a67c0d6cd9d052e95 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Thu, 19 Mar 2026 21:06:33 +0100 Subject: [PATCH 1/4] fix(text): prevent initial mount/autosize jump by precomputing text layout --- src/core/CoreTextNode.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/CoreTextNode.ts b/src/core/CoreTextNode.ts index c813f926..45e632d7 100644 --- a/src/core/CoreTextNode.ts +++ b/src/core/CoreTextNode.ts @@ -92,6 +92,15 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { this.textProps = props; this._containType = TextConstraint[props.contain]; + if ( + (props.forceLoad === true || props.parent !== null) && + this.fontHandler.isFontLoaded(this.textProps.fontFamily) === true + ) { + const resp = this.textRenderer.renderText(this.textProps); + this.handleRenderResult(resp); + this._layoutGenerated = true; + } + this.setUpdateType(UpdateType.All); } From 4d339590832489658d88adf1772c769254fda572 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Wed, 8 Apr 2026 10:10:18 +0200 Subject: [PATCH 2/4] fix(text): add eager layout check to prevent initial position jump --- src/core/CoreTextNode.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/core/CoreTextNode.ts b/src/core/CoreTextNode.ts index 45e632d7..6bc45e3f 100644 --- a/src/core/CoreTextNode.ts +++ b/src/core/CoreTextNode.ts @@ -77,6 +77,41 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { private _type: 'sdf' | 'canvas' = 'sdf'; // Default to SDF renderer + /** + * Only texts whose transform depends on measured dimensions need eager layout + * to avoid an initial position jump. + */ + private requiresLayoutForInitialTransform(props: CoreTextNodeProps): boolean { + if ( + props.mountX !== 0 || + props.mountY !== 0 || + props.pivotX !== 0 || + props.pivotY !== 0 + ) { + return true; + } + + const containType = TextConstraint[props.contain]; + + if ( + (containType & TextConstraint.width) !== 0 && + props.maxWidth > 0 && + props.textAlign !== 'left' + ) { + return true; + } + + if ( + (containType & TextConstraint.height) !== 0 && + props.maxHeight > 0 && + props.verticalAlign !== 'top' + ) { + return true; + } + + return false; + } + constructor( stage: Stage, props: CoreTextNodeProps, @@ -93,6 +128,7 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { this._containType = TextConstraint[props.contain]; if ( + this.requiresLayoutForInitialTransform(props) === true && (props.forceLoad === true || props.parent !== null) && this.fontHandler.isFontLoaded(this.textProps.fontFamily) === true ) { From 89731472c276b196e1db2bd0f99b04fa706ed299 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Wed, 8 Apr 2026 12:32:10 +0200 Subject: [PATCH 3/4] fix(text): refine eager layout check to consider parent transform dependencies --- src/core/CoreTextNode.ts | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/core/CoreTextNode.ts b/src/core/CoreTextNode.ts index c6b360da..bc71dc9a 100644 --- a/src/core/CoreTextNode.ts +++ b/src/core/CoreTextNode.ts @@ -78,38 +78,25 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { private _type: 'sdf' | 'canvas' = 'sdf'; // Default to SDF renderer /** - * Only texts whose transform depends on measured dimensions need eager layout - * to avoid an initial position jump. + * Only texts whose parent transform/layout depends on measured dimensions + * need eager layout to avoid an initial position jump. */ private requiresLayoutForInitialTransform(props: CoreTextNodeProps): boolean { - if ( - props.mountX !== 0 || - props.mountY !== 0 || - props.pivotX !== 0 || - props.pivotY !== 0 - ) { - return true; - } - - const containType = TextConstraint[props.contain]; - - if ( - (containType & TextConstraint.width) !== 0 && - props.maxWidth > 0 && - props.textAlign !== 'left' - ) { - return true; + const parent = props.parent; + if (parent === null) { + return false; } if ( - (containType & TextConstraint.height) !== 0 && - props.maxHeight > 0 && - props.verticalAlign !== 'top' + parent.mountX !== 0 || + parent.mountY !== 0 || + parent.pivotX !== 0.5 || + parent.pivotY !== 0.5 ) { return true; } - return false; + return parent.autosizer !== null || parent.parentAutosizer !== null; } constructor( @@ -128,8 +115,8 @@ export class CoreTextNode extends CoreNode implements CoreTextNodeProps { this._containType = TextConstraint[props.contain]; if ( - this.requiresLayoutForInitialTransform(props) === true && (props.forceLoad === true || props.parent !== null) && + this.requiresLayoutForInitialTransform(props) === true && this.fontHandler.isFontLoaded(this.textProps.fontFamily) === true ) { const resp = this.textRenderer.renderText(this.textProps); From be3f007aa6a75b2595f9141c858d1a4632588677 Mon Sep 17 00:00:00 2001 From: Mirko Pecora Date: Mon, 13 Apr 2026 17:49:03 +0200 Subject: [PATCH 4/4] fix: ensure filtered children are defined before pushing to array --- src/core/Autosizer.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/Autosizer.ts b/src/core/Autosizer.ts index 47978d14..5412401e 100644 --- a/src/core/Autosizer.ts +++ b/src/core/Autosizer.ts @@ -44,8 +44,10 @@ const getFilteredChildren = ( const filtered: CoreNode[] = []; while (children.length > 0) { const id = children.pop()!; - const child = childMap.get(id)!; - filtered.push(child); + const child = childMap.get(id); + if (child !== undefined) { + filtered.push(child); + } } return filtered; };