-
-
Notifications
You must be signed in to change notification settings - Fork 384
Add relative layout to UITransform
#2760
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughCentralizes Transform dirty-flag, parent-caching, and lifecycle logic into protected helpers; extends UITransform with rect-based alignment, insets, stretch modes and alignment enums; adds an extensive UITransform integration test suite and re-exports alignment enums and TransformModifyFlags. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller
participant Transform
participant ParentCache as ParentTransformCache
Caller->>Transform: set localMatrix / worldMatrix / position / worldPosition
alt localMatrix set
Transform->>Transform: _decomposeLocalMatrix(...)
Transform->>Transform: _setDirtyFlagTrue(...) / _worldAssociatedChange(...)
else worldMatrix set
Transform->>Transform: _onWorldMatrixChange()
else position set
Transform->>Transform: _onPositionChanged()
Transform->>Transform: _worldAssociatedChange(WorldPosition)
else worldPosition set
Transform->>Transform: _onWorldPositionChanged()
end
Transform->>ParentCache: _getParentTransform() (uses cache / _isParentDirty)
ParentCache-->>Transform: parent (if any)
Transform->>Transform: propagate / clear dirty flags
sequenceDiagram
autonumber
participant Child as UITransform(child)
participant Parent as UITransform(parent)
participant Base as Transform(base)
Note over Child,Parent: Alignment-driven layout & rect propagation
Child->>Child: set alignment / insets
Child->>Child: _updateSizeByAlignment() / _updatePositionByAlignment() / _updateRectByPivot()
Child->>Child: _updateWorldFlagWithSelfRectChange()
Child->>Base: alignment-aware overrides (_onPositionChanged / _onWorldMatrixChange)
Parent->>Parent: size/pivot change
Parent->>Child: _updateWorldFlagWithParentRectChange()
Child->>Child: recompute size/position/rect and dispatch flags
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (1)
packages/ui/src/component/UITransform.ts (1)
183-185: Improve null safety for child transform updatesThe optional chaining on line 184 could skip updates silently. Consider adding explicit null checks.
for (let i = 0, n = children.length; i < n; i++) { - (children[i].transform as unknown as UITransform)?._calAbsoluteByRelative(); + const childTransform = children[i].transform; + if (childTransform instanceof UITransform) { + childTransform._calAbsoluteByRelative(); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/core/src/Entity.ts(1 hunks)packages/core/src/Transform.ts(1 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/ui/src/component/UITransform.ts (2)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (1)
children(212-214)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: codecov
🔇 Additional comments (1)
packages/core/src/Transform.ts (1)
579-608: Good API design for extensibilityThe visibility changes from private to protected for
_parentChange(),_getParentTransform(), and_onPositionChanged()provide proper extension points for subclasses likeUITransform. This follows good OOP principles by allowing controlled access to lifecycle hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (4)
packages/ui/src/component/UITransform.ts (4)
78-89: Fix property assignment - use private fields instead of setters.Line 83 incorrectly uses the public setter. Use the private fields directly.
- this._left = this.right = NaN; + this._left = this._right = NaN;
129-140: Fix property assignment - use private fields instead of setters.Line 134 incorrectly uses the public setter. Use the private fields directly.
- this._top = this.bottom = NaN; + this._top = this._bottom = NaN;
267-269: Critical: Fix incorrect bitshift operator usage.Line 268 incorrectly uses the bitshift right operator
>>instead of division. This will produce incorrect results.case UITransformAlignment.Center: - position.x = (parentRect.x + (parentRect.width - localRect.width)) >> (1 + localRect.x + this._center); + position.x = parentRect.x + (parentRect.width - localRect.width) / 2 + localRect.x + this._center; break;
284-286: Critical: Fix incorrect bitshift operator usage.Line 285 has the same bitshift operator issue as line 268.
case UITransformAlignment.Middle: - position.y = (parentRect.y + (parentRect.height - localRect.height)) >> (1 + localRect.y + this._middle); + position.y = parentRect.y + (parentRect.height - localRect.height) / 2 + localRect.y + this._middle; break;
🧹 Nitpick comments (6)
packages/ui/src/component/UITransform.ts (6)
22-28: Remove redundant double-negation.The double-negation is unnecessary since numeric values are automatically coerced to boolean in conditional contexts.
override get position(): Vector3 { - if (this._isContainDirtyFlag(UITransformModifyFlags.LocalPosition) && !!this._alignment) { + if (this._isContainDirtyFlag(UITransformModifyFlags.LocalPosition) && this._alignment) { this._calAbsoluteByAlignment(); this._setDirtyFlagFalse(UITransformModifyFlags.LocalPosition); } return this._position; }
30-38: Remove redundant double-negation in matrix setters.override set localMatrix(value: Matrix) { super.localMatrix = value; - !!this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LpLm); + this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LpLm); } override set worldMatrix(value: Matrix) { super.worldMatrix = value; - !!this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LpLmWm); + this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LpLmWm); }
190-202: Remove redundant double-negation.protected override _parentChange(): void { super._parentChange(); const alignment = this._alignment; - if (!!alignment) { + if (alignment) { this._setDirtyFlagTrue(UITransformModifyFlags.LocalPosition); if ( (alignment & UITransformAlignment.Horizontal) === UITransformAlignment.LeftAndRight || (alignment & UITransformAlignment.Vertical) === UITransformAlignment.TopAndBottom ) { this._setLocalRectDirty(UITransformModifyFlags.LsLr); } } }
204-224: Remove redundant double-negation in alignment setters.private _setHorizontalAlignment(value: UITransformAlignment): void { const alignment = this._alignment; if ((alignment & UITransformAlignment.Horizontal) != value) { this._alignment = (alignment & UITransformAlignment.Vertical) | value; - if (!!value) { + if (value) { this._onPositionChanged(); value === UITransformAlignment.LeftAndRight && this._onSizeChanged(); } } } private _setVerticalAlignment(value: UITransformAlignment): void { const alignment = this._alignment; if ((alignment & UITransformAlignment.Vertical) != value) { this._alignment = (alignment & UITransformAlignment.Horizontal) | value; - if (!!value) { + if (value) { this._onPositionChanged(); value === UITransformAlignment.TopAndBottom && this._onSizeChanged(); } } }
237-254: Remove redundant double-negation.private _setLocalRectDirty(flags: UITransformModifyFlags): void { if (this._isContainDirtyFlag(flags)) return; this._setDirtyFlagTrue(flags); const children = this.entity.children; for (let i = 0, n = children.length; i < n; i++) { const transform = children[i].transform as unknown as UITransform; const alignment = transform?._alignment ?? UITransformAlignment.None; - if (!!alignment) { + if (alignment) { transform._setDirtyFlagTrue(UITransformModifyFlags.LocalPosition); if ( (alignment & UITransformAlignment.Horizontal) === UITransformAlignment.LeftAndRight || (alignment & UITransformAlignment.Vertical) === UITransformAlignment.TopAndBottom ) { transform._setLocalRectDirty(UITransformModifyFlags.LsLr); } } } }
304-313: Remove redundant double-negation in position handlers.@ignoreClone protected override _onPositionChanged(): void { super._onPositionChanged(); - !!this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LocalPosition); + this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.LocalPosition); } @ignoreClone protected override _onWorldPositionChanged(): void { super._onWorldPositionChanged(); - !!this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); + this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/src/Transform.ts(4 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🧬 Code Graph Analysis (1)
packages/core/src/Transform.ts (4)
packages/math/src/Vector3.ts (1)
Vector3(11-612)packages/core/src/clone/CloneManager.ts (2)
deepClone(45-47)ignoreClone(9-11)packages/math/src/Matrix.ts (1)
Matrix(11-1288)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 193-193: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 208-208: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 219-219: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 244-244: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 1/4)
🔇 Additional comments (7)
packages/core/src/Transform.ts (6)
22-24: LGTM! Appropriate visibility changes for inheritance.The conversion of
_positionand_worldPositionfrom private to protected is necessary and well-justified to enable the UITransform subclass to implement alignment features.
42-42: LGTM! Necessary visibility change.Converting
_localMatrixto protected enables proper matrix manipulation in subclasses.
319-343: LGTM! Consistent callback binding pattern.The addition of
_onWorldPositionChangedbinding follows the established pattern for other position/rotation callbacks.
579-602: LGTM! Essential visibility changes for subclass functionality.Converting
_parentChangeand_getParentTransformto protected enables UITransform to properly handle parent transform updates and implement alignment features.
604-621: LGTM! Well-implemented position change handlers.The visibility change for
_onPositionChangedand the new_onWorldPositionChangedmethod properly handle position updates with correct parent transform considerations.
741-755: LGTM! Necessary utility method visibility changes.Converting these dirty flag management methods to protected enables subclasses to properly manage their own dirty flags while maintaining the same robust implementation.
packages/ui/src/component/UITransform.ts (1)
1-21: LGTM! Well-structured field declarations.The use of NaN for unset alignment values and the bitmask pattern for alignment flags is a clean design choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/ui/src/component/UITransform.ts (1)
25-25: Remove redundant double-negation for cleaner code.The static analysis correctly identifies redundant double-negation operators. In boolean contexts (if statements, logical operators), explicit boolean coercion is unnecessary:
- if (!!parentRect) { + if (parentRect) {- if (!!this._alignment) { + if (this._alignment) {Apply similar changes to all flagged instances for more readable code.
Also applies to: 103-103, 135-135, 304-304, 317-317, 325-325, 349-349, 364-364, 374-374
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/src/Transform.ts(9 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 304-304: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 317-317: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 325-325: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 364-364: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: codecov
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 2/4)
🔇 Additional comments (10)
packages/core/src/Transform.ts (3)
19-19: Well-designed visibility changes to enable UITransform extension.The strategic change of key transform fields from private to protected (_position, _worldPosition, _rotationQuaternion, _scale, _localMatrix, _worldMatrix, etc.) enables the UITransform subclass to properly override and extend core transformation behavior while maintaining encapsulation. This is a clean foundation for the alignment system.
Also applies to: 22-22, 24-24, 28-28, 30-30, 32-32, 42-42, 44-44
579-582: Protected lifecycle methods enable alignment-aware behavior.The conversion of _parentChange, _getParentTransform, _onPositionChanged, and _onWorldPositionChanged to protected visibility allows UITransform to override these methods for alignment calculations and dirty flag management. The implementation maintains the original logic while providing extension points.
Also applies to: 584-602, 605-608, 611-621
719-719: Protected dirty flag methods support alignment system.Making the dirty flag helper methods protected (_updateAllWorldFlag, _isContainDirtyFlags, _isContainDirtyFlag, _setDirtyFlagTrue, _setDirtyFlagFalse) enables UITransform to manage its alignment-specific dirty flags while leveraging the existing flag management infrastructure.
Also applies to: 741-756
packages/ui/src/component/UITransform.ts (7)
11-21: Well-structured alignment system fields.The new fields provide a clean foundation for the alignment system:
- Individual alignment offset values (_left, _right, _center, etc.)
- Bitmask for tracking active alignments (_alignment)
- Cached local rectangle for efficient bounds calculation (_localRect)
22-64: Sophisticated and correct alignment position calculation.The position override properly implements alignment-based positioning:
- Correctly handles all alignment combinations (Left/Center/Right × Top/Middle/Bottom)
- Properly accounts for parent bounds and local rectangle offsets
- Maintains performance by temporarily disabling change callbacks during calculation
- Uses appropriate dirty flag management
The mathematical logic is sound for all alignment cases.
72-78: Well-implemented matrix overrides with alignment support.The localMatrix and worldMatrix overrides properly extend the base Transform behavior:
- Maintain correct matrix calculation logic from the parent class
- Add alignment-aware dirty flag management (LpLm flags when alignment is active)
- Properly handle callback management during matrix decomposition
- Use conditional flag setting based on alignment state
The implementations correctly balance performance and functionality.
Also applies to: 80-108, 110-121, 123-140
142-157: Excellent alignment property implementation.The alignment property setters demonstrate sophisticated logic:
- Proper conflict resolution (center clears left/right, middle clears top/bottom)
- Correct bitmask manipulation for tracking active alignments
- Consistent pattern across all six alignment properties
- Efficient early return on unchanged values using MathUtil.equals
The mutual exclusion logic for conflicting alignments (e.g., center vs left/right) is correctly implemented.
Also applies to: 159-174, 176-191, 193-208, 210-225, 227-242
247-266: Correct stretching calculation in size getter.The size override properly implements automatic stretching when aligned to opposite edges:
- LeftAndRight alignment:
width = parentWidth - left - right- TopAndBottom alignment:
height = parentHeight - top - bottom- Only recalculates when dirty flag is set
- Maintains proper callback management during calculation
This enables flexible responsive UI layouts.
315-329: Well-architected helper methods for alignment system.The private helper methods provide clean abstractions:
_setHorizontalAlignment/_setVerticalAlignment: Proper bitmask management with position/size recalculation_getLocalRect: Efficient cached rectangle calculation based on size and pivot_setLocalRectDirty: Recursive propagation of layout changes to aligned children- Lifecycle method overrides: Clean integration with parent transform behavior
The recursive propagation in
_setLocalRectDirtycorrectly handles nested UI hierarchies where child elements depend on parent layout changes.Also applies to: 331-340, 342-359, 361-376, 378-389, 392-396
403-429: Well-designed enum extensions for UI alignment system.The new enums provide proper flag management:
UITransformModifyFlags:
- Extends base flags without conflicts
- Logical bit flag values (powers of 2)
- Useful combined flags (LsLr, LpLm) for common operations
- Clear separation of UI-specific flags
UITransformAlignment:
- Proper bit flag design for horizontal/vertical separation
- Combined flags (LeftAndRight, TopAndBottom) for stretching behavior
- Efficient bitmask operations with Horizontal/Vertical masks
Also applies to: 431-445
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (10)
packages/ui/src/component/UITransform.ts (10)
25-25: Remove redundant double-negation.The double-negation operator is unnecessary here since the expression will already be coerced to a boolean in the conditional context.
- if (!!parentRect) { + if (parentRect) {
103-103: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!this._alignment) { + if (this._alignment) {
135-135: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!this._alignment) { + if (this._alignment) {
186-186: Fix formatting issue.There's a formatting issue that needs to be addressed for better readability.
- this._left = this._right = NaN; + this._left = this._right = NaN;
237-237: Fix formatting issue.There's a formatting issue that needs to be addressed for better readability.
- this._top = this._bottom = NaN; + this._top = this._bottom = NaN;
304-304: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!alignment) { + if (alignment) {
317-317: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!value) { + if (value) {
325-325: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!value) { + if (value) {
349-349: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!alignment) { + if (alignment) {
364-364: Remove redundant double-negation.The double-negation operator is unnecessary here.
- if (!!this._alignment) { + if (this._alignment) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 304-304: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 317-317: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 325-325: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 364-364: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🪛 GitHub Check: lint
packages/ui/src/component/UITransform.ts
[failure] 237-237:
Insert ⏎·······
[failure] 186-186:
Insert ⏎·······
🪛 ESLint
packages/ui/src/component/UITransform.ts
[error] 186-186: Insert ⏎·······
(prettier/prettier)
[error] 237-237: Insert ⏎·······
(prettier/prettier)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: codecov
🔇 Additional comments (16)
packages/ui/src/component/UITransform.ts (16)
1-1: Import statement looks good.The imports are well-organized and all appear to be necessary for the UI alignment functionality.
11-20: Well-structured private fields for alignment system.The private fields are properly organized with appropriate decorators. The
_localRectuses@ignoreClonewhich is correct for a cached computed value.
22-64: Position getter has robust alignment calculation logic.The position calculation correctly handles different alignment scenarios with proper parent rectangle checks and temporary callback disabling.
66-70: Position setter correctly avoids infinite loops.Good implementation that prevents triggering alignment recalculations by directly copying the value instead of using the setter logic.
72-108: Local matrix override handles alignment state properly.The implementation correctly manages dirty flags and handles the alignment recalculation trigger appropriately.
110-140: World matrix override is well-implemented.The world matrix calculation and setter properly handle parent transforms and alignment state management.
142-191: Alignment property setters have sound logic.The horizontal alignment properties (left, right, center) correctly manage mutual exclusivity and update alignment flags appropriately.
193-242: Vertical alignment properties implemented correctly.The vertical alignment properties (top, bottom, middle) follow the same sound pattern as horizontal alignment with proper flag management.
247-266: Size getter handles stretch alignment correctly.The implementation properly calculates stretched dimensions based on parent rect and alignment constraints.
290-296: Constructor properly binds event handlers.The constructor correctly binds the size and pivot change handlers which are essential for the alignment system.
301-313: Parent change override handles alignment updates correctly.The method properly triggers position and size recalculations when the parent changes and alignment is active.
315-329: Alignment helper methods are well-designed.The
_setHorizontalAlignmentand_setVerticalAlignmentmethods correctly update flags and trigger appropriate recalculations.
331-359: Local rect calculation and dirty propagation are robust.The
_getLocalRectmethod correctly calculates the local rectangle from size and pivot, while_setLocalRectDirtyproperly propagates changes to child transforms.
362-375: Position change handlers correctly manage dirty flags.Both
_onPositionChangedand_onWorldPositionChangedproperly set appropriate dirty flags based on alignment state.
378-396: Size and pivot change handlers are well-implemented.The handlers correctly manage dirty flags and dispatch update events for the alignment system.
403-440: Enums are well-designed for the alignment system.The
UITransformModifyFlagsandUITransformAlignmentFlagsenums provide a clean, efficient way to manage state flags with logical combinations for common operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
packages/ui/src/component/UITransform.ts (4)
22-71: Fix redundant double-negation and approve the alignment logicThe position calculation logic is well-implemented with proper handling of different alignment cases and performance optimizations. However, there's a redundant double-negation on line 25.
Apply this diff to remove the redundant double-negation:
- if (!!parentRect) { + if (parentRect) {
72-141: Fix redundant double-negations and approve matrix handlingThe matrix override implementations are sophisticated and correctly handle the complex relationship between local/world matrices and UI alignment. The dirty flag management and callback handling are well-designed.
Apply these diffs to remove redundant double-negations:
- if (!!this._alignment) { + if (this._alignment) {- if (!!this._alignment) { + if (this._alignment) {
292-377: Fix redundant double-negations and approve lifecycle managementThe constructor and lifecycle method overrides are well-implemented. The parent change handling correctly manages dirty flags for alignment-aware transforms, and the callback binding ensures proper reactivity.
Apply these diffs to remove redundant double-negations:
- if (!!alignment) { + if (alignment) {- if (!!this._alignment) { + if (this._alignment) {
317-398: Fix redundant double-negations and approve helper methodsThe private helper methods are well-designed and implement the core alignment system effectively. The recursive dirty flag propagation and local rect caching are good optimizations.
Apply these diffs to remove redundant double-negations:
- if (!!value) { + if (value) {- if (!!value) { + if (value) {- if (!!alignment) { + if (alignment) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🧬 Code Graph Analysis (1)
packages/ui/src/component/UITransform.ts (4)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Transform.ts (7)
position(61-63)position(65-69)rotationQuaternion(150-166)rotationQuaternion(168-178)scale(215-217)scale(219-223)Transform(10-863)packages/core/src/Entity.ts (4)
parent(201-203)parent(205-207)children(212-214)transform(155-157)packages/core/src/2d/sprite/Sprite.ts (2)
pivot(167-169)pivot(171-173)
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 306-306: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 319-319: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 327-327: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 351-351: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 366-366: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: build (22.x, macos-latest)
🔇 Additional comments (4)
packages/ui/src/component/UITransform.ts (4)
1-21: LGTM: Well-structured class foundationThe imports, class declaration, and private field setup are properly implemented. The use of decorators for cloning behavior and the alignment flag system using bit operations is efficient and appropriate.
142-244: LGTM: Consistent and well-designed alignment propertiesThe alignment property getters and setters are consistently implemented with proper mutual exclusion logic. The use of
MathUtil.equalsfor comparisons and NaN for unset values is appropriate. The delegation to helper methods promotes code reuse and maintainability.
249-268: LGTM: Correct stretch behavior implementationThe size getter correctly implements stretch behavior for UI elements. When both opposing alignment values are set (left+right or top+bottom), the element properly stretches to fill the available space minus the specified margins.
405-442: LGTM: Well-designed flag systemThe flag enums are properly designed with clear naming conventions and non-conflicting bit values. The composite flags (LsLr, LpLm, etc.) are useful optimizations for common flag combinations, and the separation of horizontal/vertical alignment flags provides good flexibility.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev/1.6 #2760 +/- ##
===========================================
+ Coverage 78.88% 79.00% +0.12%
===========================================
Files 843 845 +2
Lines 89944 90611 +667
Branches 8786 8962 +176
===========================================
+ Hits 70951 71586 +635
- Misses 18856 18885 +29
- Partials 137 140 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (7)
packages/ui/src/component/UITransform.ts (7)
25-25: Remove redundant double-negation.The double-negation is unnecessary as the value will be coerced to boolean in the conditional context.
- if (!!parentRect) { + if (parentRect) {
103-103: Remove redundant double-negation.Simplify the boolean check for better readability.
- if (!!this._alignment) { + if (this._alignment) {
135-135: Remove redundant double-negation.Simplify the boolean check for consistency.
- if (!!this._alignment) { + if (this._alignment) {
311-311: Remove redundant double-negation.Simplify the boolean check for better readability.
- if (!!alignment) { + if (alignment) {
338-338: Remove redundant double-negation.Simplify the boolean check for consistency.
- if (!!value) { + if (value) {
346-346: Remove redundant double-negation.Simplify the boolean check for consistency.
- if (!!value) { + if (value) {
382-382: Remove redundant double-negation.Simplify the boolean check for consistency.
- if (!!this._alignment) { + if (this._alignment) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/src/Transform.ts(10 hunks)packages/ui/src/component/UITransform.ts(3 hunks)
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 338-338: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 346-346: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 382-382: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/src/Transform.ts
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 338-338: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 346-346: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 382-382: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codecov
🔇 Additional comments (8)
packages/ui/src/component/UITransform.ts (8)
11-20: Well-structured alignment system foundation.The private field declarations are well-organized and follow good practices:
- Proper use of
@ignoreClonefor the cached_rectfield- Consistent initialization of alignment values with
NaNfor optional properties- Clean bitmask approach with
UITransformAlignmentFlags.None
22-64: Sophisticated position calculation with good performance optimization.The position getter implementation is well-designed:
- Proper dirty flag management to avoid unnecessary recalculations
- Smart callback disabling during internal calculations to prevent recursion
- Clear separation of horizontal and vertical alignment logic
- Correct mathematical calculations for each alignment case
72-140: Excellent matrix override implementation.The matrix getter/setter overrides demonstrate sophisticated handling of:
- Dirty flag optimization for performance
- Proper matrix decomposition and recomposition
- Correct parent-child matrix relationships
- Smart integration with the alignment system
The callback management during matrix operations prevents unwanted side effects.
142-244: Well-designed alignment property system.The alignment property implementations demonstrate excellent design:
- Consistent pattern across all six properties
- Proper value equality checks to prevent unnecessary updates
- Correct mutual exclusion logic between conflicting alignments
- Clean separation between horizontal and vertical alignment management
- Appropriate use of helper methods for triggering layout updates
The mutual exclusion logic correctly handles edge cases like setting
centerclearingleft/rightvalues.
250-266: Excellent responsive sizing implementation.The size getter enhancement perfectly handles stretched layouts:
- Dynamic width calculation for
LeftAndRightalignment using parent bounds- Dynamic height calculation for
TopAndBottomalignment- Proper dirty flag management for performance optimization
- Smart callback disabling to prevent infinite recursion
This enables responsive UI elements that automatically adjust to parent container changes.
295-306: Proper event handling and hierarchy management.The constructor and
_parentChangeoverride are well-implemented:
- Correct binding of change handlers for size and pivot properties
- Proper propagation of layout updates when parent transforms change
- Clean integration with the dirty flag system through
_transferFlagsThis ensures layout consistency is maintained throughout the transform hierarchy.
308-424: Sophisticated layout management system.The helper methods implement a comprehensive layout system:
- Complex but correct dirty flag propagation logic in
_transferFlags- Proper alignment update handling with position/size recalculations
- Efficient local rect caching with appropriate invalidation
- Correct child propagation for maintaining hierarchy consistency
The interdependency management between position, size, alignment, and dirty flags is well-architected.
431-473: Well-architected flag system.The enum definitions demonstrate excellent design:
UITransformModifyFlagsappropriately extends base transform flags with UI-specific additions- Convenient combined flag constants like
LmLp,WmWpfor common operationsUITransformAlignmentFlagsuses efficient bit flag patterns for alignment state management- Logical separation between horizontal and vertical alignment flags
- Clear naming and organization of flag combinations
This flag system enables efficient dirty state tracking and alignment management.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
22-70: Excellent alignment-aware position implementation with minor cleanup needed.The position getter correctly implements sophisticated alignment calculations with proper dirty flag management and callback handling. The position setter is appropriately simplified for the alignment system.
Fix the redundant double-negation flagged by static analysis:
- if (!!parentRect) { + if (parentRect) {
72-140: Robust matrix handling with alignment awareness.The matrix property overrides correctly implement alignment-aware transform management with proper dirty flag handling and parent-child relationships.
Fix redundant double-negations flagged by static analysis:
- if (!!this._alignment) { + if (this._alignment) { this._setDirtyFlagTrue(UITransformModifyFlags.LmLp); } else { this._setDirtyFlagFalse(UITransformModifyFlags.LmLp); }- if (!!this._alignment) { + if (this._alignment) { this._setDirtyFlagTrue(UITransformModifyFlags.WorldMatrix); } else { this._setDirtyFlagFalse(UITransformModifyFlags.WorldMatrix); }
303-396: Solid override implementations for alignment-aware transform lifecycle.The method overrides correctly handle alignment state changes and dirty flag propagation throughout the transform hierarchy.
Fix redundant double-negations flagged by static analysis:
- if (!!alignment) { + if (alignment) {- if (!!value) { + if (value) {- if (!!value) { + if (value) {- if (!!this._alignment) { + if (this._alignment) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/core/src/Transform.ts(10 hunks)packages/ui/src/component/UITransform.ts(3 hunks)
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/src/Transform.ts
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build (22.x, macos-latest)
- GitHub Check: codecov
🔇 Additional comments (6)
packages/ui/src/component/UITransform.ts (6)
1-1: LGTM! Well-structured foundation for the alignment system.The import additions and private field declarations properly establish the alignment system infrastructure. The use of
@ignoreClonefor the cached_rectfield and NaN initialization for alignment offsets is appropriate.Also applies to: 12-20
142-244: Excellent alignment property implementation with consistent patterns.The alignment property getters and setters are well-designed with proper mutual exclusivity handling, appropriate floating-point comparisons, and consistent bitwise flag management.
249-268: Well-implemented dynamic size calculation for stretched layouts.The size getter correctly handles dynamic sizing for stretched alignment modes while maintaining proper dirty flag management and callback handling patterns.
295-298: Appropriate constructor enhancements for alignment system.The constructor properly binds event handlers for size and pivot changes to support the alignment system.
308-428: Comprehensive and well-structured helper method implementations.The helper methods effectively support the alignment system with proper flag propagation, efficient caching, and consistent state management patterns.
435-477: Well-designed enum definitions for efficient flag management.The enum extensions and new alignment flags are properly structured with non-conflicting bit patterns and logical groupings that support efficient bitwise operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
22-64: Remove redundant double-negation.The position calculation logic is correct, but line 25 has redundant double-negation that can be simplified.
- if (!!parentRect) { + if (parentRect) {
72-140: Remove redundant double-negations in matrix methods.The matrix override logic is correct, but there are redundant double-negations that can be simplified.
- if (!!this._alignment) { + if (this._alignment) { this._setDirtyFlagTrue(UITransformModifyFlags.LmLp); } else { this._setDirtyFlagFalse(UITransformModifyFlags.LmLp); }- if (!!this._alignment) { + if (this._alignment) { this._setDirtyFlagTrue(UITransformModifyFlags.WorldMatrix); } else { this._setDirtyFlagFalse(UITransformModifyFlags.WorldMatrix); }
303-428: Remove redundant double-negations in private methods.The private method implementations are logically correct, but several instances of redundant double-negation can be simplified for cleaner code.
- if (!!alignment) { + if (alignment) {- if (!!value) { + if (value) {- if (!!value) { + if (value) {- !!this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); + this._alignment && this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(3 hunks)
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: codecov
- GitHub Check: e2e (22.x, 1/4)
🔇 Additional comments (5)
packages/ui/src/component/UITransform.ts (5)
1-21: LGTM! Well-structured field declarations.The imports and private field declarations are properly organized with appropriate decorators for the alignment system.
142-244: LGTM! Well-implemented alignment properties.The alignment property getters and setters are consistently implemented with proper flag management and mutual exclusivity handling between conflicting alignments.
249-268: LGTM! Correct dynamic size calculation.The size getter properly handles dynamic sizing for stretched UI elements with appropriate dirty flag management.
435-477: LGTM! Well-structured enum definitions.The enum definitions for modify flags and alignment flags are properly organized with appropriate bitwise values and meaningful combinations.
1-477: Excellent implementation of UI alignment system.This is a comprehensive and well-architected implementation of relative layout capabilities for UITransform. The alignment calculations are mathematically sound, dirty flag management is proper, and the code follows established patterns. The only improvements needed are removing redundant double-negations flagged by static analysis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
packages/ui/src/component/UITransform.ts (6)
22-64: Remove redundant double-negation in parent rectangle check.The alignment-aware position calculation logic is well-implemented, but line 25 contains redundant double-negation as flagged by static analysis.
- if (!!parentRect) { + if (parentRect) {The mathematical calculations for different alignment cases appear correct, and the temporary disabling of value change callbacks prevents recursive updates.
72-108: Remove redundant double-negation in alignment check.The matrix computation and decomposition logic is correct, but line 103 contains redundant double-negation.
- if (!!this._alignment) { + if (this._alignment) {The alignment-aware dirty flag management is a good addition to handle layout recalculations when matrices change.
110-140: Remove redundant double-negation in alignment check.The world matrix computation is correctly implemented with proper parent hierarchy handling, but line 135 contains redundant double-negation.
- if (!!this._alignment) { + if (this._alignment) {The matrix inversion and local matrix update logic is sound.
303-337: Remove redundant double-negation in alignment check.The hierarchy change propagation logic is well-implemented but line 311 contains redundant double-negation.
- if (!!alignment) { + if (alignment) {The
_transferFlagsmethod correctly handles:
- Conditional flag propagation based on alignment state
- Special handling for stretched alignment modes
- Efficient dirty flag containment checks to avoid unnecessary work
- Recursive propagation to child transforms
This is essential for maintaining layout consistency across the UI hierarchy.
339-380: Remove redundant double-negations in alignment checks.The alignment helper methods are well-structured but contain redundant double-negations flagged by static analysis.
- if (!!value) { + if (value) {Apply this fix to both lines 341 and 349.
The helper methods provide excellent abstractions:
- Clean separation of horizontal and vertical alignment management
- Proper triggering of position and size recalculations when needed
- Efficient cached rectangle computation in
_getLocalRect- Sound bitwise operations for flag isolation
383-428: Remove redundant double-negation in alignment check.The event handler overrides are correctly implemented but line 385 contains redundant double-negation.
- if (!!this._alignment) { + if (this._alignment) {The event handlers properly integrate with the alignment system:
- Position change handlers manage alignment-specific dirty flags appropriately
- Size and pivot handlers trigger necessary recalculations
- Proper update flag manager dispatching for change notifications
- Efficient recursive propagation to child transforms
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(3 hunks)
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🧰 Additional context used
🧠 Learnings (1)
packages/ui/src/component/UITransform.ts (2)
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-07-19T03:26:39.344Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
Learnt from: cptbtptpbcptdtptp
PR: #2165
File: packages/xr/src/loader/XRSceneExtendParser.ts:0-0
Timestamp: 2024-10-09T01:11:17.858Z
Learning: The user cptbtptpbcptdtptp resolved the issue regarding the use of this in a static context in the XRSceneExtendParser class by replacing it with the class name.
🪛 Biome (1.9.4)
packages/ui/src/component/UITransform.ts
[error] 25-25: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 103-103: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 135-135: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 311-311: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 341-341: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 349-349: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
[error] 385-385: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: build (22.x, windows-latest)
- GitHub Check: codecov
🔇 Additional comments (5)
packages/ui/src/component/UITransform.ts (5)
1-1: Well-structured field declarations for the alignment system.The new private fields are properly typed and decorated. The use of
@ignoreCloneon_rectis appropriate since it's a computed cache.Also applies to: 11-20
142-244: Well-implemented alignment property system.The alignment property getters and setters are correctly implemented with:
- Proper value comparison using
MathUtil.equalsto avoid unnecessary updates- Sound bitwise flag manipulation for alignment state management
- Appropriate mutual exclusion logic (e.g., setting
centerclearsleftandright)- Consistent pattern across all alignment properties
The logic correctly handles the relationships between conflicting alignment modes.
249-268: Excellent dynamic size calculation for stretched layouts.The modified size getter correctly implements dynamic dimension calculation for stretched alignment modes:
- Handles horizontal stretching (
LeftAndRight) and vertical stretching (TopAndBottom) independently- Uses parent rectangle dimensions minus alignment offsets
- Proper callback management prevents recursive updates
- Efficient dirty flag-based recalculation
This is essential functionality for responsive UI layouts.
295-298: Proper event handler binding in constructor.The constructor correctly binds the size and pivot change handlers to maintain proper
thiscontext when called as callbacks.
435-477: Well-designed enum extensions for the alignment system.The enum extensions are excellently structured:
UITransformModifyFlags:
- Adds necessary flags for alignment-aware dirty state management
- Logical flag combinations (e.g.,
LmLp,WmWp) improve code readability- Proper bit patterns that don't conflict with existing flags
UITransformAlignmentFlags:
- Clean separation of horizontal (0x1-0x7) and vertical (0x8-0x38) bit ranges
- Logical combinations like
LeftAndRightandTopAndBottomcorrectly defined- Efficient bit masking with
HorizontalandVerticalgroup flagsThis design enables efficient bitwise operations throughout the alignment system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/Transform.ts (1)
301-310: Guard Matrix.invert in worldMatrix setterMatrix.invert may return null for non-invertible parents (e.g., zero scale). Avoid multiplying with null.
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat42); - Matrix.multiply(Transform._tempMat42, value, this._localMatrix); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat42); + if (inv) { + Matrix.multiply(inv, value, this._localMatrix); + } else { + // Fallback: treat as root when parent matrix is singular. + this._localMatrix.copyFrom(value); + } + } else { this._localMatrix.copyFrom(value); }
♻️ Duplicate comments (3)
tests/src/ui/UITransform.test.ts (2)
299-302: Avoid duplicating internal flags; import enum insteadRedefining UITransformModifyFlags is brittle. Import from the package if publicly exported; otherwise assert via public APIs instead of bits.
-enum UITransformModifyFlags { - Size = 0x200, - Pivot = 0x400 -} +import { UITransformModifyFlags } from "@galacean/engine-ui";
10-22: Refactor: don’t use async describe; move setup into beforeAll/afterAllAsync describe causes tests to register unreliably in Vitest. Move async work to hooks and clean up the engine to prevent leaks.
-import { describe, expect, it } from "vitest"; +import { beforeAll, afterAll, describe, expect, it } from "vitest"; @@ -describe("UITransform", async () => { - const canvas = document.createElement("canvas"); - const engine = await WebGLEngine.create({ canvas }); - const webCanvas = engine.canvas; - webCanvas.width = 750; - webCanvas.height = 1334; - const scene = engine.sceneManager.scenes[0]; - const root = scene.createRootEntity("root"); - - // Parent with UITransform (via UICanvas), children created under it will inherit UITransform automatically - const canvasEntity = root.createChild("canvas"); - canvasEntity.addComponent(UICanvas); +describe("UITransform", () => { + let engine: WebGLEngine; + let root: any; + let canvasEntity: any; + + beforeAll(async () => { + const canvas = document.createElement("canvas"); + engine = await WebGLEngine.create({ canvas }); + const webCanvas = engine.canvas; + webCanvas.width = 750; + webCanvas.height = 1334; + const scene = engine.sceneManager.scenes[0]; + root = scene.createRootEntity("root"); + canvasEntity = root.createChild("canvas"); + canvasEntity.addComponent(UICanvas); + }); + + afterAll(async () => { + await engine?.destroy?.(); + });packages/core/src/Transform.ts (1)
642-651: Guard Matrix.invert in world→local mappingSame singular-matrix issue when writing worldPosition.
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat41); - Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat41); + if (inv) { + Vector3.transformCoordinate(worldPosition, inv, this._position); + } else { + this._position.copyFrom(worldPosition); + } + } else { this._position.copyFrom(worldPosition); }
🧹 Nitpick comments (4)
tests/src/ui/UITransform.test.ts (2)
2-7: Style: fix prettier import formattingMatch repo prettier: collapse named imports to a single line.
-import { - HorizontalAlignmentFlags, - UICanvas, - UITransform, - VerticalAlignmentFlags, -} from "@galacean/engine-ui"; +import { HorizontalAlignmentFlags, UICanvas, UITransform, VerticalAlignmentFlags } from "@galacean/engine-ui";
275-277: Style: remove extra blank linesPrettier flags these empty lines.
- - -packages/ui/src/component/UITransform.ts (2)
261-266: Re-setting WorldPosition dirty in _onWorldPositionChanged can loopCalling super clears the flag; setting it true again may cause extra churn. If the goal is to notify dependents, prefer _worldAssociatedChange gating instead of raw dirty bit.
- if (!!this._horizontalAlignment || !!this._verticalAlignment) { - this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); - } + // If notification is needed, gate by containment to avoid churn: + // if (!this._isContainDirtyFlag(UITransformModifyFlags.WorldPosition)) { + // this._worldAssociatedChange(UITransformModifyFlags.WorldPosition); + // }
403-417: Avoid duplicating core flags in UITransformModifyFlagsThese values mirror TransformModifyFlags and can drift. Reuse core flags and only add UI-specific ones (Size, Pivot).
-import { - Entity, - MathUtil, - Matrix, - Quaternion, - Rect, - Transform, - Vector2, - Vector3, - deepClone, - ignoreClone -} from "@galacean/engine"; +import { + Entity, + MathUtil, + Matrix, + Quaternion, + Rect, + Transform, + TransformModifyFlags as TMF, + Vector2, + Vector3, + deepClone, + ignoreClone +} from "@galacean/engine"; @@ -export enum UITransformModifyFlags { - None = 0x0, - LocalEuler = 0x1, - LocalQuat = 0x2, - WorldPosition = 0x4, - LocalMatrix = 0x40, - WorldMatrix = 0x80, - Size = 0x200, - Pivot = 0x400, - - /** World matrix | world position. */ - WmWp = WorldMatrix | WorldPosition, - /** WorldMatrix | WorldPosition | WorldEuler | WorldQuat | WorldScale | WorldUniformScaling */ - WmWpWeWqWsWus = 0x1bc -} +export enum UITransformModifyFlags { + None = TMF.WmWp & ~TMF.WmWp, // 0 + // Reuse core bits: + LocalEuler = TMF.LocalEuler, + LocalQuat = TMF.LocalQuat, + WorldPosition = TMF.WorldPosition, + LocalMatrix = TMF.LocalMatrix, + WorldMatrix = TMF.WorldMatrix, + // UI-specific: + Size = 0x200, + Pivot = 0x400, + // Common combos: + WmWp = TMF.WmWp, + WmWpWeWqWsWus = TMF.WmWpWeWqWsWus +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
packages/core/src/Transform.ts(7 hunks)packages/ui/src/component/UITransform.ts(4 hunks)tests/src/ui/UITransform.test.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/core/src/Transform.tspackages/ui/src/component/UITransform.ts
🧬 Code graph analysis (3)
packages/core/src/Transform.ts (5)
packages/math/src/Vector3.ts (3)
Vector3(11-612)scale(207-212)scale(483-489)packages/math/src/Matrix.ts (4)
Matrix(11-1288)rotationQuaternion(206-242)scale(670-694)scale(1166-1169)packages/physics-lite/src/LiteTransform.ts (6)
position(36-38)position(40-46)rotationQuaternion(52-63)rotationQuaternion(65-72)scale(110-112)scale(114-120)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
tests/src/ui/UITransform.test.ts (1)
packages/ui/src/component/UITransform.ts (1)
UITransform(18-397)
🪛 ESLint
tests/src/ui/UITransform.test.ts
[error] 2-7: Replace ⏎··HorizontalAlignmentFlags,⏎··UICanvas,⏎··UITransform,⏎··VerticalAlignmentFlags,⏎ with ·HorizontalAlignmentFlags,·UICanvas,·UITransform,·VerticalAlignmentFlags·
(prettier/prettier)
[error] 275-277: Delete ⏎⏎
(prettier/prettier)
[error] 302-302: Insert ⏎
(prettier/prettier)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: codecov
🔇 Additional comments (11)
packages/core/src/Transform.ts (2)
74-83: Good: worldPosition uses position when no parentThis aligns world/local coupling with UI overrides (e.g., alignment), avoiding stale _position reads.
249-253: Good: localMatrix builds from position getterEnsures layout-side adjustments apply before matrix composition.
packages/ui/src/component/UITransform.ts (9)
61-85: Alignment setter behavior looks rightPosition-only for Left/Right/Center; position+size for LeftAndRight. Matches intended relative layout priority.
94-119: Margins trigger minimal recompute; goodFinite-checks and conditional size updates avoid unnecessary work.
135-159: Vertical alignment mirrors horizontal correctlyTop/Middle/Bottom vs TopAndBottom handling is symmetric and clear.
238-248: Matrix→local decompose plus alignment recalcThis reasserts alignment after setting local/world matrices. Verify no unexpected overrides when alignment is None.
Would you like a focused test that sets localMatrix under each alignment mode to confirm expected precedence?
250-252: Potential: skipping base _onWorldMatrixChange leaves WorldMatrix dirtyWhen any alignment is active, base clearing is skipped. Ensure this won’t cause repeated recomputation. Consider always clearing WorldMatrix but keep layout-specific flags separate.
I can propose a patch to clear WorldMatrix while preserving layout recalcs if needed.
268-306: Position formulas are correctLeft/Center/Right and Top/Middle/Bottom computations match rect math and tests.
308-324: Good: stretched size clamped non-negativePrevents invalid sizes when margins exceed parent size.
355-368: Propagation on self-rect changes looks rightInverts the contain-check correctly; dispatches WmWp and notifies children.
94-134: Confirm enums are bit-flagsSetters use bitwise checks (value & Flag). Ensure Horizontal/Vertical enums are defined as bit-flags; if they’re plain enums, switch to equality checks.
I can adjust conditionals once you confirm the enum definitions.
Also applies to: 168-207
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/core/src/Transform.ts (1)
297-310: Guard parent inverse in worldMatrix setterIf the parent’s world matrix is singular, the unguarded invert/multiply yields invalid locals.
Apply:
const parent = this._getParentTransform(); if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat42); - Matrix.multiply(Transform._tempMat42, value, this._localMatrix); + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat42); + if (inv) { + Matrix.multiply(inv, value, this._localMatrix); + } else { + // Fallback: treat as root if non-invertible + this._localMatrix.copyFrom(value); + } } else { this._localMatrix.copyFrom(value); } this.localMatrix = this._localMatrix; this._onWorldMatrixChange();packages/ui/src/component/UITransform.ts (2)
42-46: Enforce non-negative size in setterNegative width/height produce inverted rects and break layout. Clamp here to guarantee invariants.
set size(value: Vector2) { const { _size: size } = this; if (size === value) return; - (size.x !== value.x || size.y !== value.y) && size.copyFrom(value); + if (size.x !== value.x || size.y !== value.y) { + // Clamp to [0, +∞) + const nx = Math.max(0, value.x); + const ny = Math.max(0, value.y); + size.set(nx, ny); + } }
230-236: Clone misses alignment and marginsCloned UITransform loses layout (alignment flags and offsets), causing visual divergence.
override _cloneTo(target: UITransform, srcRoot: Entity, targetRoot: Entity): void { // @ts-ignore super._cloneTo(target, srcRoot, targetRoot); target.size.copyFrom(this._size); target.pivot.copyFrom(this._pivot); + // Copy alignment and margins + target.horizontalAlignment = this._horizontalAlignment; + target.verticalAlignment = this._verticalAlignment; + target.left = this._left; + target.right = this._right; + target.center = this._center; + target.top = this._top; + target.bottom = this._bottom; + target.middle = this._middle; }
♻️ Duplicate comments (2)
packages/core/src/Transform.ts (1)
642-653: Also guard invert in world→local position mappingUnprotected inversion can propagate NaNs when the parent is non-invertible. Same concern previously raised.
Apply:
const parent = this._getParentTransform(); if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat41); - Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat41); + if (inv) { + Vector3.transformCoordinate(worldPosition, inv, this._position); + } else { + this._position.copyFrom(worldPosition); + } } else { this._position.copyFrom(worldPosition); } this._setDirtyFlagFalse(TransformModifyFlags.WorldPosition);packages/ui/src/component/UITransform.ts (1)
1-14: Stop duplicating core Transform flags; reference themUITransformModifyFlags redefines core bits (LocalMatrix, WorldMatrix, etc.). This is brittle if core values change. Reference core flags directly and reserve UI-only bits for Size/Pivot.
Apply:
-import { - Entity, - MathUtil, - Matrix, - Quaternion, - Rect, - Transform, - Vector2, - Vector3, - deepClone, - ignoreClone -} from "@galacean/engine"; +import { + Entity, + MathUtil, + Matrix, + Quaternion, + Rect, + Transform, + TransformModifyFlags as TMF, + Vector2, + Vector3, + deepClone, + ignoreClone +} from "@galacean/engine"; @@ export enum UITransformModifyFlags { - None = 0x0, - LocalEuler = 0x1, - LocalQuat = 0x2, - WorldPosition = 0x4, - LocalMatrix = 0x40, - WorldMatrix = 0x80, - Size = 0x200, - Pivot = 0x400, - - /** World matrix | world position. */ - WmWp = WorldMatrix | WorldPosition, - /** WorldMatrix | WorldPosition | WorldEuler | WorldQuat | WorldScale | WorldUniformScaling */ - WmWpWeWqWsWus = 0x1bc + None = 0x0, + // Reuse core flags + LocalEuler = TMF.LocalEuler, + LocalQuat = TMF.LocalQuat, + WorldPosition = TMF.WorldPosition, + LocalMatrix = TMF.LocalMatrix, + WorldMatrix = TMF.WorldMatrix, + // UI-only flags + Size = 0x200, + Pivot = 0x400, + // Reuse core composites + WmWp = TMF.WmWp, + WmWpWeWqWsWus = TMF.WmWpWeWqWsWus }Also applies to: 403-417
🧹 Nitpick comments (2)
packages/core/src/Transform.ts (1)
616-634: Minor: simplify parent lookupEvery
Entityhas atransform; the loop that skips entities without transforms can be simplified for maintainability.- let parentCache: Transform = null; - let parent = this._entity.parent; - while (parent) { - const transform = parent.transform; - if (transform) { - parentCache = transform; - break; - } else { - parent = parent.parent; - } - } + let parentCache: Transform = null; + let parent = this._entity.parent; + if (parent) parentCache = parent.transform;packages/ui/src/component/UITransform.ts (1)
55-59: Clamp pivot to [0, 1]Out-of-range pivots yield surprising rects. Clamp for robustness.
set pivot(value: Vector2) { const { _pivot: pivot } = this; if (pivot === value) return; - (pivot.x !== value.x || pivot.y !== value.y) && pivot.copyFrom(value); + if (pivot.x !== value.x || pivot.y !== value.y) { + pivot.set(MathUtil.clamp(value.x, 0, 1), MathUtil.clamp(value.y, 0, 1)); + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/core/src/Transform.ts(6 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.tspackages/core/src/Transform.ts
🧬 Code graph analysis (2)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
packages/core/src/Transform.ts (5)
packages/math/src/Matrix.ts (4)
Matrix(11-1288)rotationQuaternion(206-242)scale(670-694)scale(1166-1169)packages/physics-lite/src/LiteTransform.ts (6)
position(36-38)position(40-46)rotationQuaternion(52-63)rotationQuaternion(65-72)scale(110-112)scale(114-120)packages/math/src/Vector3.ts (3)
scale(207-212)scale(483-489)Vector3(11-612)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: codecov
🔇 Additional comments (22)
packages/core/src/Transform.ts (4)
53-55: Good change: make parent-dirty visible to subclassesPromoting
_isParentDirtyto protected cleanly enables UITransform to hook parent-cache invalidation.
80-83: worldPosition fallback to local is correctUsing
worldPosition.copyFrom(this.position)when no parent preserves prior semantics and reduces duplication.
249-253: Compute localMatrix from public accessorsBuilding the affine from
this.position/this.rotationQuaternion/this._scaleis consistent with the new dirty-paths and avoids bypassing hooks.
590-593: No-op world-matrix hook is fineClearing only the WorldMatrix bit here centralizes behavior and lets subclasses override selectively.
packages/ui/src/component/UITransform.ts (18)
68-85: Alignment setter side-effects look correctPosition invalidation on Left/Right/Center and size+position on LeftAndRight matches expected stretch behavior.
94-103: Left margin updates: OKConditional position and stretch-size recalculation are appropriate and avoid redundant work.
111-119: Right margin updates: OKSymmetric with left; looks good.
128-133: Center offset update: OKNo size adjustments on center-only is correct.
142-159: Vertical alignment setter mirrors horizontal: OKMiddle and TopAndBottom paths mirror center/stretch behavior correctly.
168-176: Top margin path: OKTriggers position and stretch-size updates only when relevant flags are set.
185-193: Bottom margin path: OKMatches top logic; good.
202-207: Middle offset update: OKCorrectly limited to Middle alignment.
214-220: Wiring size/pivot change handlers is correctBinding and assigning
_onValueChangedhooks ensures reactive layout.
225-228: Parent change propagation: OKMarking parent-dirty and kicking rect-dependent world flags downstream is appropriate.
238-248: Override of _decomposeLocalMatrix: OKDecomposing the provided matrix, then recomputing position under alignment honors “relative > absolute” design.
250-253: World-matrix clearing delegated appropriatelySkipping base clearing when alignment is active prevents premature world-flag resolution; good.
260-266: Ignore world-position writes under active alignmentRe-flagging WorldPosition after the base conversion ensures absolute writes don’t override relative layout. Matches stated design choice.
268-306: Position formulas look correctLeft/Center/Right and Top/Middle/Bottom equations are consistent with rect math (child edge equals parent edge ± margins).
308-324: Stretch size clamped to non-negativeGood safeguard against over-constrained layouts.
333-345: Size-change pipeline is soundRecomputes stretch, rect, propagates world flags, and dispatches Size; minimal, correct.
355-368: Self-rect change propagation: OKConditional world-flag dispatch plus child fan-out avoids redundant updates.
370-396: Parent-rect change handling: OKCorrectly recomputes stretch, rect, and position then propagates, with short-circuiting when flags already set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ui/src/component/UITransform.ts (1)
230-236: Clone misses layout state (alignments and margins).Cloned UI elements lose alignment/margins, producing different layout.
Apply:
override _cloneTo(target: UITransform, srcRoot: Entity, targetRoot: Entity): void { // @ts-ignore super._cloneTo(target, srcRoot, targetRoot); - target.size.copyFrom(this._size); - target.pivot.copyFrom(this._pivot); + target.size.copyFrom(this._size); + target.pivot.copyFrom(this._pivot); + // Copy layout state without triggering recalcs during clone. + (target as any)._horizontalAlignment = this._horizontalAlignment; + (target as any)._verticalAlignment = this._verticalAlignment; + (target as any)._left = this._left; + (target as any)._right = this._right; + (target as any)._center = this._center; + (target as any)._top = this._top; + (target as any)._bottom = this._bottom; + (target as any)._middle = this._middle; + (target as any)._rect.copyFrom(this._rect); }I can add a focused test asserting cloned nodes preserve alignment and margins.
♻️ Duplicate comments (1)
packages/core/src/Transform.ts (1)
642-653: Also guard inversion in world→local position mapping.Apply:
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat41); - Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat41); + if (inv) { + Vector3.transformCoordinate(worldPosition, inv, this._position); + } else { + this._position.copyFrom(worldPosition); + } + } else { this._position.copyFrom(worldPosition); }
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
255-261: Short-circuit worldPosition writes under active alignment to reduce churn.Avoid doing world→local then immediately overriding via alignment and re-dirtying WorldPosition.
Apply:
- protected override _onWorldPositionChanged(): void { - super._onWorldPositionChanged(); - if (!!this._horizontalAlignment || !!this._verticalAlignment) { - this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); - } - } + protected override _onWorldPositionChanged(): void { + if (this._horizontalAlignment || this._verticalAlignment) { + // Ignore external world-position writes when relative layout is active. + this._calPosition(); + this._setDirtyFlagFalse(UITransformModifyFlags.WorldPosition); + return; + } + super._onWorldPositionChanged(); + }
303-319: Clamp comment vs. behavior mismatch.Comment says “must be greater than 0” but code clamps to >= 0. Align the comment to “non-negative” or clamp to a tiny epsilon.
Apply either:
- // The values of size must be greater than 0. + // The values of size must be non-negative.or
- size.x = Math.max(parentRect.width - this._left - this._right, 0); + size.x = Math.max(parentRect.width - this._left - this._right, 1e-6);(and similarly for size.y)
398-412: Deduplicate flag values by reusing core TransformModifyFlags.Prevents silent drift if core bits change.
Apply:
@@ -import { +import { Entity, MathUtil, Matrix, Quaternion, Rect, Transform, + TransformModifyFlags as TMF, Vector2, Vector3, deepClone, ignoreClone } from "@galacean/engine"; @@ export enum UITransformModifyFlags { None = 0x0, - LocalEuler = 0x1, - LocalQuat = 0x2, - WorldPosition = 0x4, - LocalMatrix = 0x40, - WorldMatrix = 0x80, + LocalEuler = TMF.LocalEuler, + LocalQuat = TMF.LocalQuat, + WorldPosition = TMF.WorldPosition, + LocalMatrix = TMF.LocalMatrix, + WorldMatrix = TMF.WorldMatrix, Size = 0x200, Pivot = 0x400, /** World matrix | world position. */ - WmWp = WorldMatrix | WorldPosition, + WmWp = TMF.WmWp, /** WorldMatrix | WorldPosition | WorldEuler | WorldQuat | WorldScale | WorldUniformScaling */ - WmWpWeWqWsWus = 0x1bc + WmWpWeWqWsWus = TMF.WmWpWeWqWsWus }Also applies to: 1-12
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/core/src/Transform.ts(4 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.tspackages/core/src/Transform.ts
🧬 Code graph analysis (2)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
packages/core/src/Transform.ts (3)
packages/physics-lite/src/LiteTransform.ts (6)
position(36-38)position(40-46)rotationQuaternion(52-63)rotationQuaternion(65-72)scale(110-112)scale(114-120)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: codecov
🔇 Additional comments (7)
packages/core/src/Transform.ts (3)
584-588: Good fix: now decomposes the passed-in matrix (not this._localMatrix).This resolves the earlier bug and keeps dirty flags consistent.
610-615: World-associated dispatch helper looks correct.Only newly added flags are dispatched; avoids redundant events.
297-310: Matrix.invert returns void, not a boolean
Matrix.invert(a, out) mutatesoutand does not return success/failure (its return value is alwaysundefined). Capturing its return value and branching on it won’t work. To guard against non-invertible parent matrices, compute the determinant (e.g. via a new Matrix.determinant method) and skip inversion on singular matrices, or extend the API with atryInvert(a, out): booleanvariant that returns false on failure.Likely an incorrect or invalid review comment.
packages/ui/src/component/UITransform.ts (4)
249-253: Relative layout correctly overrides absolute position writes.Calling _calPosition before delegating to super keeps alignment priority as intended.
263-301: Alignment formulas look correct.Left/Center/Right and Top/Middle/Bottom computations correctly use parent/local rects and margins.
263-266: Confirm parent is always a UITransform; otherwise, define a fallback.If a UITransform can be parented under a non-UI Transform, parentRect is undefined and alignment becomes a no-op. Either assert UI parentage or add a documented fallback.
Would you like me to add a dev-assert (only in non-prod) and a graceful fallback?
Also applies to: 303-306
222-228: World-flag propagation for rect changes looks sound.Self and parent-rect change paths update LocalMatrix and dispatch newly added world flags; child propagation is gated to avoid redundant dispatch.
Also applies to: 350-363, 365-391
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (7)
packages/ui/src/component/UITransform.ts (7)
68-85: Canonicalize horizontalAlignment to supported combosPrevent illegal mixes (e.g., Left|Center) from becoming a silent no-op by normalizing to None | Left | Center | Right | LeftAndRight before applying side effects.
set horizontalAlignment(value: HorizontalAlignmentFlags) { - const current = this._horizontalAlignment; - if (current === value) return; - this._horizontalAlignment = value; - switch (value) { + // Canonicalize: only allow None | Left | Center | Right | LeftAndRight + const LR = HorizontalAlignmentFlags.Left | HorizontalAlignmentFlags.Right; + const allowed = HorizontalAlignmentFlags.Left | HorizontalAlignmentFlags.Right | HorizontalAlignmentFlags.Center; + let v = value & allowed; + if ((v & LR) === LR) v = HorizontalAlignmentFlags.LeftAndRight; + else if ((v & HorizontalAlignmentFlags.Center) && (v & LR)) v = HorizontalAlignmentFlags.Center; + if (v === 0) v = HorizontalAlignmentFlags.None; + + const current = this._horizontalAlignment; + if (current === v) return; + this._horizontalAlignment = v; + switch (v) { case HorizontalAlignmentFlags.Left: case HorizontalAlignmentFlags.Right: case HorizontalAlignmentFlags.Center: this._onPositionChanged(); break; case HorizontalAlignmentFlags.LeftAndRight: this._onPositionChanged(); this._onSizeChanged(); break; default: break; } }
142-159: Canonicalize verticalAlignment to supported combosNormalize to None | Top | Middle | Bottom | TopAndBottom to avoid undefined behavior with mixed flags.
set verticalAlignment(value: VerticalAlignmentFlags) { - const current = this._verticalAlignment; - if (current === value) return; - this._verticalAlignment = value; - switch (value) { + // Canonicalize: only allow None | Top | Middle | Bottom | TopAndBottom + const TB = VerticalAlignmentFlags.Top | VerticalAlignmentFlags.Bottom; + const allowed = VerticalAlignmentFlags.Top | VerticalAlignmentFlags.Bottom | VerticalAlignmentFlags.Middle; + let v = value & allowed; + if ((v & TB) === TB) v = VerticalAlignmentFlags.TopAndBottom; + else if ((v & VerticalAlignmentFlags.Middle) && (v & TB)) v = VerticalAlignmentFlags.Middle; + if (v === 0) v = VerticalAlignmentFlags.None; + + const current = this._verticalAlignment; + if (current === v) return; + this._verticalAlignment = v; + switch (v) { case VerticalAlignmentFlags.Top: case VerticalAlignmentFlags.Bottom: case VerticalAlignmentFlags.Middle: this._onPositionChanged(); break; case VerticalAlignmentFlags.TopAndBottom: this._onPositionChanged(); this._onSizeChanged(); break; default: break; } }
238-243: Avoid unnecessary _calPosition when alignment is offMinor perf/readability: guard the call; behavior unchanged.
protected override _decomposeLocalMatrix(matrix: Matrix, pos: Vector3, quat: Quaternion, scale: Vector3): void { matrix.decompose(pos, quat, scale); - this._calPosition(); + if (this._horizontalAlignment || this._verticalAlignment) { + this._calPosition(); + } this._setDirtyFlagTrue(UITransformModifyFlags.LocalEuler | UITransformModifyFlags.LocalMatrix); this._setDirtyFlagFalse(UITransformModifyFlags.LocalQuat); }
256-261: Redundant world-position dirty flagBase already handles world-position dirtiness; setting it again under alignment adds noise without benefit.
protected override _onWorldPositionChanged(): void { super._onWorldPositionChanged(); - if (!!this._horizontalAlignment || !!this._verticalAlignment) { - this._setDirtyFlagTrue(UITransformModifyFlags.WorldPosition); - } }
263-266: Type-narrow parentTransform instead of casting through unknownSafer narrowing avoids accidental misuse when the parent isn’t a UITransform.
- const parentRect = (this._getParentTransform() as unknown as UITransform)?._rect; + const parent = this._getParentTransform(); + const parentRect = parent instanceof UITransform ? parent._rect : undefined;Apply similarly in _calSize.
Also applies to: 303-306
309-315: Comment nit: “greater than 0” → “non-negative”You clamp to 0, so the comment should reflect non-negativity.
- // The values of size must be greater than 0. + // Size values are clamped to be non-negative.
401-414: Don’t duplicate core Transform flags; ensure parity or reuseRedefining shared bits (LocalMatrix, WorldMatrix, WorldPosition, etc.) is brittle. Prefer reusing core flags or add a dev-only parity assert to catch drift early.
Option A (preferred): reuse core flags.
- Import core TransformModifyFlags and reference them where needed, keeping UI-only flags (Size, Pivot, LocalRect, LocalPosition) in this enum or as consts.
Option B: add a parity assert (dev-only) that validates your numeric values match core at startup; keep UI-only bits local.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.ts
🧬 Code graph analysis (1)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (4)
scale(215-217)scale(219-223)position(61-63)position(65-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: codecov
🔇 Additional comments (2)
packages/ui/src/component/UITransform.ts (2)
270-301: Alignment formulas look correct (left/center/right, top/middle/bottom)The position equations properly anchor edges/centers relative to parentRect and local rect. Nice touch disabling callbacks during mutation. This matches the intended “relative layout overrides absolute” behavior noted earlier.
328-340: LGTM: Size/rect propagation under stretchRecomputing size under LeftAndRight/TopAndBottom, then rect and world propagation, aligns with the product decision that relative layout takes precedence over absolute size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/ui/src/component/UITransform.ts (1)
400-414: Deduplicate core Transform flags; reuse from core or assert parityReplicating core flag bit values is brittle. Reuse TransformModifyFlags for shared bits; keep UI-only flags locally. If reuse isn’t possible, add a dev-time parity assertion.
Preferred change:
+import { TransformModifyFlags as TMF } from "@galacean/engine"; @@ export enum UITransformModifyFlags { - None = 0x0, - LocalEuler = 0x1, - LocalQuat = 0x2, - WorldPosition = 0x4, - LocalMatrix = 0x40, - WorldMatrix = 0x80, + None = 0x0, + LocalEuler = TMF.LocalEuler, + LocalQuat = TMF.LocalQuat, + WorldPosition = TMF.WorldPosition, + LocalMatrix = TMF.LocalMatrix, + WorldMatrix = TMF.WorldMatrix, Size = 0x200, Pivot = 0x400, - WmWp = WorldMatrix | WorldPosition, - WmWpWeWqWsWus = 0x1bc + WmWp = TMF.WorldMatrix | TMF.WorldPosition, + // Keep this composite in sync with core: + WmWpWeWqWsWus = TMF.WorldMatrix | TMF.WorldPosition | TMF.WorldEuler | TMF.WorldQuat | TMF.WorldScale | TMF.WorldUniformScaling }Fallback (if importing TMF here causes layering issues): add a one-time dev assert at startup comparing these bit values against core.
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
245-247: Prefer explicit if over boolean short-circuit for side effectsImproves readability and avoids mixing boolean expressions with a void call.
- protected override _onWorldMatrixChange() { - !this._horizontalAlignment && !this._verticalAlignment && super._onWorldMatrixChange(); - } + protected override _onWorldMatrixChange() { + if (!this._horizontalAlignment && !this._verticalAlignment) { + super._onWorldMatrixChange(); + } + }
249-253: Remove @ignoreClone on methodsignoreClone is for fields; applying it to methods is unnecessary and pollutes clone metadata.
- @ignoreClone protected override _onPositionChanged(): void { @@ - @ignoreClone protected override _onWorldPositionChanged(): void { @@ - @ignoreClone private _onSizeChanged(): void { @@ - @ignoreClone private _onPivotChanged(): void {Also applies to: 255-261, 328-340, 342-348
263-266: Tighten parent rect access (avoid double cast to unknown)Minor TS hygiene; keeps the cast localized and clearer.
- const parentRect = (this._getParentTransform() as unknown as UITransform)?._rect; + const parent = this._getParentTransform() as UITransform | undefined; + const parentRect = parent?._rect;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.ts
🧬 Code graph analysis (1)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (4)
scale(215-217)scale(219-223)position(61-63)position(65-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codecov
🔇 Additional comments (2)
packages/ui/src/component/UITransform.ts (2)
270-283: Alignment formulas look correctLeft/Center/Right and Top/Middle/Bottom positioning math matches expected rect-edge/center relationships and honors pivot. This also aligns with the intended “relative > absolute” priority noted earlier.
Also applies to: 285-297
303-319: Good: stretched size is clampedClamping the stretched size to non-negative prevents invalid widths/heights under over-constrained margins.
| @ignoreClone | ||
| private _onSizeChanged(): void { | ||
| if ( | ||
| this._horizontalAlignment === HorizontalAlignmentFlags.LeftAndRight || | ||
| this._verticalAlignment === VerticalAlignmentFlags.TopAndBottom | ||
| ) { | ||
| this._calSize(); | ||
| } | ||
| this._calRect(); | ||
| this._updateWorldFlagWithSelfRectChange(); | ||
| // @ts-ignore | ||
| this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Clamp size for non-stretch cases too
Direct size changes can still be negative and will corrupt rect/placement math. Clamp here as well (not just in stretch), before recalculating the rect.
Apply:
private _onSizeChanged(): void {
if (
this._horizontalAlignment === HorizontalAlignmentFlags.LeftAndRight ||
this._verticalAlignment === VerticalAlignmentFlags.TopAndBottom
) {
this._calSize();
}
+ // Ensure non-negative size in all cases to keep rect math valid.
+ const size = this._size;
+ // @ts-ignore
+ size._onValueChanged = null;
+ size.x = Math.max(0, size.x);
+ size.y = Math.max(0, size.y);
+ // @ts-ignore
+ size._onValueChanged = this._onSizeChanged;
this._calRect();
this._updateWorldFlagWithSelfRectChange();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @ignoreClone | |
| private _onSizeChanged(): void { | |
| if ( | |
| this._horizontalAlignment === HorizontalAlignmentFlags.LeftAndRight || | |
| this._verticalAlignment === VerticalAlignmentFlags.TopAndBottom | |
| ) { | |
| this._calSize(); | |
| } | |
| this._calRect(); | |
| this._updateWorldFlagWithSelfRectChange(); | |
| // @ts-ignore | |
| this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); | |
| } | |
| @ignoreClone | |
| private _onSizeChanged(): void { | |
| if ( | |
| this._horizontalAlignment === HorizontalAlignmentFlags.LeftAndRight || | |
| this._verticalAlignment === VerticalAlignmentFlags.TopAndBottom | |
| ) { | |
| this._calSize(); | |
| } | |
| // Ensure non-negative size in all cases to keep rect math valid. | |
| const size = this._size; | |
| // @ts-ignore | |
| size._onValueChanged = null; | |
| size.x = Math.max(0, size.x); | |
| size.y = Math.max(0, size.y); | |
| // @ts-ignore | |
| size._onValueChanged = this._onSizeChanged; | |
| this._calRect(); | |
| this._updateWorldFlagWithSelfRectChange(); | |
| // @ts-ignore | |
| this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); | |
| } |
🤖 Prompt for AI Agents
In packages/ui/src/component/UITransform.ts around lines 328-340, the
_onSizeChanged method needs to clamp the transform's explicit size for
non-stretch cases as well so negative direct size changes don't corrupt rect
math; before calling this._calRect() (and before dispatching the Size flag)
clamp width/height to a non-negative minimum (or call the module's existing
clamp/normalize helper if one exists), e.g. ensure this._width = Math.max(0,
this._width) and this._height = Math.max(0, this._height) (or equivalent), then
proceed to _calRect(), _updateWorldFlagWithSelfRectChange(), and the dispatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/Transform.ts (1)
301-310: Guard non-invertible parent in worldMatrix write path.If
parent.worldMatrixis singular (e.g., zero scale),Matrix.invertcan fail; current code proceeds with an invalid inverse.Apply:
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat42); - Matrix.multiply(Transform._tempMat42, value, this._localMatrix); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat42); + if (inv) { + Matrix.multiply(inv, value, this._localMatrix); + } else { + // Parent not invertible; best-effort: treat as root. + this._localMatrix.copyFrom(value); + } + } else { this._localMatrix.copyFrom(value); } this.localMatrix = this._localMatrix; this._onWorldMatrixChange();
♻️ Duplicate comments (3)
tests/src/ui/UITransform.test.ts (2)
10-22: Fix async test setup structure.This is the same issue raised in previous reviews about async describe blocks not registering tests reliably in Vitest.
366-369: Export UITransformModifyFlags instead of redefining.The enum is being redefined locally instead of importing from the canonical source, which makes it brittle to changes.
packages/core/src/Transform.ts (1)
643-653: Also guard invert in world→local position mapping.Same singular-parent issue as above when writing
worldPosition.protected _onWorldPositionChanged(): void { const worldPosition = this._worldPosition; const parent = this._getParentTransform(); if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat41); - Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat41); + if (inv) { + Vector3.transformCoordinate(worldPosition, inv, this._position); + } else { + // Parent not invertible; best-effort: treat as root. + this._position.copyFrom(worldPosition); + } } else { this._position.copyFrom(worldPosition); } this._setDirtyFlagFalse(TransformModifyFlags.WorldPosition); }
🧹 Nitpick comments (4)
tests/src/ui/UITransform.test.ts (1)
324-324: Fix prettier formatting issues.The static analysis indicates formatting problems with line breaks in this section. While the test logic is correct, addressing these formatting issues will ensure consistent code style.
Also applies to: 326-326
packages/ui/src/component/UITransform.ts (1)
398-405: Consider exposing UITransformModifyFlags publicly or using core flags.Based on previous review feedback, consider either:
- Exporting this enum via the public API (in
packages/ui/src/index.ts) so tests and external code can import it reliably- Reusing
TransformModifyFlagsfrom core for shared flag values and defining only UI-specific additions hereThis would reduce maintenance burden and prevent tests from needing to redefine the enum values.
packages/core/src/Transform.ts (1)
610-615: Nit: avoid dispatching when no new bits are added.Minor micro-opt to skip a no-op dispatch.
protected _worldAssociatedChange(type: number): void { - const dispatchFlags = type & ~this._dirtyFlag; + const dispatchFlags = type & ~this._dirtyFlag; this._dirtyFlag |= type; - this._entity._updateFlagManager.dispatch(dispatchFlags); + if (dispatchFlags !== 0) { + this._entity._updateFlagManager.dispatch(dispatchFlags); + } }packages/ui/src/enums/HorizontalAlignmentMode.ts (1)
1-12: Make flags semantics explicit; document valid combos; tighten JSDocClarify this is a flags enum, encode values with shifts/OR for readability, and state that Center is mutually exclusive with Left/Right. Also note alignment precedence per UITransform behavior and add a since tag.
-/** Horizontal alignment mode. */ -export enum HorizontalAlignmentMode { - /** No horizontal alignment. */ - None = 0, - /** Left-aligned, `alignLeft` drives `position.x`. */ - Left = 0x1, - /** Right-aligned, `alignRight` drives `position.x`. */ - Right = 0x2, - /** Horizontal stretch, `alignLeft` and `alignRight` drive `position.x` and `size.x`. */ - LeftAndRight = 0x3, - /** Center-aligned, `alignCenter` drives `position.x`. */ - Center = 0x4 -} +/** + * Horizontal alignment mode (flags). + * + * Valid states: + * - None + * - Left + * - Right + * - Left | Right (aka LeftAndRight; stretch) + * - Center (mutually exclusive with Left/Right) + * + * Note: When not `None`, alignment overrides absolute `position.x` in UITransform. + * @since 1.6 + */ +export enum HorizontalAlignmentMode { + /** No horizontal alignment. */ + None = 0, + /** Left-aligned, `alignLeft` drives `position.x`. */ + Left = 1 << 0, + /** Right-aligned, `alignRight` drives `position.x`. */ + Right = 1 << 1, + /** Horizontal stretch, `alignLeft` and `alignRight` drive `position.x` and `size.x`. */ + LeftAndRight = Left | Right, + /** Center-aligned, `alignCenter` drives `position.x` (do not combine with Left/Right). */ + Center = 1 << 2 +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
packages/core/src/Transform.ts(5 hunks)packages/core/src/index.ts(1 hunks)packages/ui/src/component/UITransform.ts(4 hunks)packages/ui/src/enums/HorizontalAlignmentMode.ts(1 hunks)packages/ui/src/enums/VerticalAlignmentMode.ts(1 hunks)packages/ui/src/index.ts(1 hunks)tests/src/ui/UITransform.test.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ui/src/index.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.tspackages/core/src/Transform.ts
🧬 Code graph analysis (5)
packages/ui/src/enums/VerticalAlignmentMode.ts (1)
packages/ui/src/index.ts (1)
VerticalAlignmentMode(25-25)
packages/ui/src/enums/HorizontalAlignmentMode.ts (1)
packages/ui/src/index.ts (1)
HorizontalAlignmentMode(24-24)
tests/src/ui/UITransform.test.ts (1)
packages/ui/src/component/UITransform.ts (1)
UITransform(20-396)
packages/ui/src/component/UITransform.ts (5)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/ui/src/index.ts (2)
HorizontalAlignmentMode(24-24)VerticalAlignmentMode(25-25)packages/core/src/index.ts (2)
Entity(11-11)TransformModifyFlags(17-17)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
packages/core/src/Transform.ts (5)
packages/physics-lite/src/LiteTransform.ts (6)
position(36-38)position(40-46)rotationQuaternion(52-63)rotationQuaternion(65-72)scale(110-112)scale(114-120)packages/math/src/Matrix.ts (4)
rotationQuaternion(206-242)scale(670-694)scale(1166-1169)Matrix(11-1288)packages/math/src/Vector3.ts (3)
scale(207-212)scale(483-489)Vector3(11-612)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)
🪛 ESLint
tests/src/ui/UITransform.test.ts
[error] 2-7: Replace ⏎··HorizontalAlignmentMode,⏎··UICanvas,⏎··UITransform,⏎··VerticalAlignmentMode,⏎ with ·HorizontalAlignmentMode,·UICanvas,·UITransform,·VerticalAlignmentMode·
(prettier/prettier)
[error] 324-324: Insert ⏎·······
(prettier/prettier)
[error] 326-326: Insert ⏎·······
(prettier/prettier)
[error] 339-342: Replace ⏎··});⏎⏎ with ··});
(prettier/prettier)
[error] 369-369: Insert ⏎
(prettier/prettier)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: codecov
🔇 Additional comments (34)
packages/ui/src/enums/VerticalAlignmentMode.ts (1)
1-13: LGTM - Consistent with horizontal alignment design.The enum maintains parity with
HorizontalAlignmentModeusing the same hex value pattern. Clear documentation of how each mode drives position and size calculations.packages/core/src/index.ts (1)
17-17: LGTM - Exposes TransformModifyFlags publicly.This enables the UI layer and external consumers to access the centralized dirty-flag system, which supports the enhanced transform hierarchy introduced in this PR.
tests/src/ui/UITransform.test.ts (5)
23-60: LGTM - Comprehensive event dispatch testing.The test properly verifies that size and pivot changes dispatch the correct flags through the entity's update flag manager, which is crucial for the hierarchical dirty propagation system.
62-188: LGTM - Thorough alignment testing coverage.The tests comprehensively cover both horizontal and vertical alignment modes under default and custom parent configurations, including stretch modes. The expected values properly account for parent size, pivot, and alignment insets.
189-272: LGTM - Excellent dirty propagation testing.These tests effectively verify that rect changes propagate correctly through the hierarchy, both for self-rect changes (pivot/size) and parent-rect changes. The test cases cover the critical scenarios for layout invalidation and recalculation.
274-339: LGTM - Validates alignment priority over manual transforms.These tests correctly verify the design decision that relative layout (alignment) takes priority over absolute positioning, as confirmed in the retrieved learnings. The tests ensure layout consistency is maintained even when manual transform operations are attempted.
344-363: LGTM - World transform integration testing.The test properly verifies that alignment-driven local positions compose correctly with parent world transforms, ensuring the layout system works within the broader transform hierarchy.
packages/ui/src/component/UITransform.ts (19)
1-15: LGTM - Well-structured imports for UI layout system.The imports bring together core engine primitives with the new alignment enums to support the comprehensive UI layout features being introduced.
21-35: LGTM - Clean state initialization for alignment system.The private fields are well-organized with logical defaults: rect initialized to match the default size/pivot, alignment values defaulted to zero, and alignment modes set to None. The
@ignoreClonedecorator on_rectis appropriate since it's computed from size/pivot.
63-87: LGTM - Proper alignment mode handling with selective recalculation.The setter correctly triggers position recalculation for all alignment modes and additionally triggers size recalculation specifically for stretch mode (LeftAndRight), which is the expected behavior.
89-135: LGTM - Robust alignment inset property implementations.The alignment property setters properly validate finite values, use
MathUtil.equalsfor floating-point comparison, and intelligently trigger only the necessary recalculations based on the current alignment mode. The bitwise flag checks correctly determine when position and/or size updates are needed.
137-161: LGTM - Consistent vertical alignment implementation.The vertical alignment setter maintains the same pattern as horizontal alignment, correctly triggering position updates for all modes and adding size recalculation for the TopAndBottom stretch mode.
163-209: LGTM - Consistent vertical inset properties.The vertical alignment properties follow the same robust pattern as the horizontal ones: finite value validation, proper equality checks, and selective recalculation based on active alignment modes.
214-222: LGTM - Proper event handler binding in constructor.The constructor correctly binds the size and pivot change handlers and wires them to the Vector2 value change callbacks, establishing the foundation for the reactive layout system.
224-230: LGTM - Parent change propagation.The
_parentChangemethod properly marks parent as dirty and propagates rect changes through the hierarchy with appropriate transform flags.
240-245: LGTM - Override handles alignment-aware decomposition.The method correctly decomposes the matrix, recalculates alignment-driven position, and updates the appropriate dirty flags. This ensures alignment is preserved when transforms are applied via matrix operations.
247-249: LGTM - Conditional world matrix change handling.The override correctly bypasses the base class behavior when alignment is active, preventing conflicts between alignment-driven positioning and world matrix updates.
251-255: LGTM - Alignment-aware position change handling.The method correctly recalculates position when alignment is active before delegating to the base implementation, ensuring alignment constraints are maintained.
257-263: LGTM - World position dirty flag management.The override properly sets the WorldPosition dirty flag when alignment is active, ensuring world-space changes are tracked correctly in the alignment system.
265-303: LGTM - Comprehensive position calculation logic.The
_calPositionmethod correctly calculates local position from parent rect and alignment settings. The logic properly handles all alignment modes with appropriate offset calculations. The temporary disabling of the value change callback prevents infinite recursion during recalculation.
305-321: LGTM - Stretch size calculation with proper clamping.The
_calSizemethod correctly calculates stretched sizes from parent dimensions and alignment insets, with proper clamping to prevent negative values. The temporary callback disabling prevents recursion.
323-328: LGTM - Efficient rect calculation.The
_calRectmethod efficiently computes the local rect from size and pivot using standard UI layout formulas.
330-342: LGTM - Comprehensive size change handling.The method properly recalculates stretch-driven sizes, updates the rect, propagates world flags, and dispatches the Size event. The logic flow ensures all dependent calculations are updated in the correct order.
344-350: LGTM - Pivot change handling.The method correctly updates the rect, propagates world flags, and dispatches the Pivot event when pivot changes occur.
352-365: LGTM - Self rect change propagation.The method properly recalculates position when alignment is active, sets appropriate dirty flags, triggers world-associated changes, and propagates rect changes to children. The flag management ensures efficient hierarchy updates.
367-395: LGTM - Parent rect change propagation with stretch handling.The method correctly handles parent-driven changes by recalculating stretch-driven sizes when needed, updating position for alignment, managing dirty flags appropriately, and propagating changes to children. The conditional Size dispatch for stretch changes is correct.
packages/core/src/Transform.ts (8)
53-55: Good: expose_isParentDirtyto subclasses.This enables UITransform (and others) to invalidate the cached parent transform when layout-related ancestry changes.
257-278: Local-matrix setter decomposition path looks correct.Using
_decomposeLocalMatrix(...)centralizes the split and correctly reattaches value-change hooks and world-flag propagation.
584-588: Fix confirmed:_decomposeLocalMatrixnow uses itsmatrixparameter.This resolves the previous setter/back-prop corruption.
590-593: Hook_onWorldMatrixChangeis a sensible default.No-op (besides clearing flag) is fine in core; derived classes should
super._onWorldMatrixChange()then extend.Please confirm UITransform overrides this hook (or
localMatrixgetter) to trigger relative-layout recomputation before consumers read world/local matrices.
594-609: Dirty-flag helpers centralize bit ops.These reduce duplication and improve readability.
616-634: Parent-transform cache logic looks good; verify invalidation coverage.Cache is reset only via
_parentChange(). Ensure ancestry reparenting triggers_parentChange()for descendants so the nearest-transform cache stays correct.
636-641: Local position change propagation is correct.Marks
LocalMatrixdirty and fans out world-position updates.
877-913: Flag table reads consistently.Bit groupings (e.g.,
WmWsWus,WmWpWeWqWs) match their components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ui/src/component/UITransform.ts (1)
232-238: Cloning omits alignment state and insets (breaks layout of clones)_cloneTo copies only size/pivot; alignment modes and offsets are lost, so cloned UI elements won’t keep their relative layout. Copy these fields too.
Apply this diff:
override _cloneTo(target: UITransform, srcRoot: Entity, targetRoot: Entity): void { // @ts-ignore super._cloneTo(target, srcRoot, targetRoot); - target.size.copyFrom(this._size); - target.pivot.copyFrom(this._pivot); + // Preserve alignment modes and insets. + target._horizontalAlignment = this._horizontalAlignment; + target._verticalAlignment = this._verticalAlignment; + target._alignLeft = this._alignLeft; + target._alignRight = this._alignRight; + target._alignCenter = this._alignCenter; + target._alignTop = this._alignTop; + target._alignBottom = this._alignBottom; + target._alignMiddle = this._alignMiddle; + // Then copy size/pivot (hooks will recalc rect/position if needed). + target.size.copyFrom(this._size); + target.pivot.copyFrom(this._pivot); }
♻️ Duplicate comments (1)
packages/ui/src/component/UITransform.ts (1)
330-342: Clamp explicit size to non-negative in non-stretch casesNegative width/height can corrupt rect math and placements when users set size directly. Clamp here, not only in stretch.
Apply this diff:
private _onSizeChanged(): void { if ( this._horizontalAlignment === HorizontalAlignmentMode.LeftAndRight || this._verticalAlignment === VerticalAlignmentMode.TopAndBottom ) { this._calSize(); } + // Ensure non-negative size for direct (non-stretch) edits as well. + // @ts-ignore + const size = this._size; + // @ts-ignore + size._onValueChanged = null; + size.x = Math.max(0, size.x); + size.y = Math.max(0, size.y); + // @ts-ignore + size._onValueChanged = this._onSizeChanged; this._calRect(); this._updateWorldFlagWithSelfRectChange(); // @ts-ignore this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); }Please add/verify a test that sets size to negative values and asserts width/height are clamped to 0 (and that rect/position remain stable).
🧹 Nitpick comments (2)
packages/ui/src/component/UITransform.ts (2)
257-263: Remove redundant WorldPosition dirty setsuper._onWorldPositionChanged() already marks world position dirty. The extra set under alignment is unnecessary.
Apply this diff:
protected override _onWorldPositionChanged(): void { super._onWorldPositionChanged(); - if (!!this._horizontalAlignment || !!this._verticalAlignment) { - this._setDirtyFlagTrue(TransformModifyFlags.WorldPosition); - } }
287-296: Document anchor choice for stretch on Y (TopAndBottom uses bottom for position)Behavior is fine, but make it explicit in a short comment to avoid confusion: stretch computes size from top+bottom and anchors position to bottom (symmetrically, LeftAndRight anchors to left).
Apply this diff:
switch (this._verticalAlignment) { case VerticalAlignmentMode.Top: position.y = parentRect.y + parentRect.height - rect.y - rect.height - this._alignTop; break; case VerticalAlignmentMode.Middle: position.y = parentRect.y + parentRect.height * 0.5 - rect.y - rect.height * 0.5 + this._alignMiddle; break; case VerticalAlignmentMode.Bottom: case VerticalAlignmentMode.TopAndBottom: + // For stretch (TopAndBottom), size is from top+bottom; position anchors to bottom. position.y = parentRect.y - rect.y + this._alignBottom; break;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.ts
🧬 Code graph analysis (1)
packages/ui/src/component/UITransform.ts (4)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/index.ts (2)
Entity(11-11)TransformModifyFlags(17-17)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codecov
🔇 Additional comments (1)
packages/ui/src/component/UITransform.ts (1)
265-303: LGTM: Alignment-driven position calculation is correct and avoids re-entrancyFormulas for Left/Center/Right and Top/Middle/Bottom are sound, and the temporary nulling of _onValueChanged prevents recursive updates. This also enforces the intended priority of relative layout over absolute positioning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ui/src/component/UITransform.ts (1)
232-238: Cloning loses alignment configuration_cloneTo() copies size/pivot but not alignment modes or insets. Cloned UI elements will silently drop relative layout, diverging from source behavior.
Apply:
override _cloneTo(target: UITransform, srcRoot: Entity, targetRoot: Entity): void { // @ts-ignore super._cloneTo(target, srcRoot, targetRoot); target.size.copyFrom(this._size); target.pivot.copyFrom(this._pivot); + // Preserve alignment configuration. + target._horizontalAlignment = this._horizontalAlignment; + target._verticalAlignment = this._verticalAlignment; + target._alignLeft = this._alignLeft; + target._alignRight = this._alignRight; + target._alignCenter = this._alignCenter; + target._alignTop = this._alignTop; + target._alignBottom = this._alignBottom; + target._alignMiddle = this._alignMiddle; + target._updateRectByPivot(); }
♻️ Duplicate comments (1)
packages/ui/src/component/UITransform.ts (1)
330-342: Clamp explicit size to non-negative values (non-stretch path)Direct size edits can set negative width/height and corrupt rect/placement math. Stretch path clamps, but non-stretch path doesn’t.
Apply:
private _onSizeChanged(): void { + // Clamp explicit size to non-negative to keep rect math valid. + const size = this._size; + // @ts-ignore + const prevCb = size._onValueChanged; + // @ts-ignore + size._onValueChanged = null; + size.x = Math.max(0, size.x); + size.y = Math.max(0, size.y); + // @ts-ignore + size._onValueChanged = prevCb; if ( this._horizontalAlignment === HorizontalAlignmentMode.LeftAndRight || this._verticalAlignment === VerticalAlignmentMode.TopAndBottom ) { this._updateSizeByAlignment(); } this._updateRectByPivot(); this._updateWorldFlagWithSelfRectChange(); // @ts-ignore this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); }
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
240-245: Make LocalPosition dirtiness explicit after alignment override_decomposeLocalMatrix() overrides position via alignment but doesn’t mark LocalPosition dirty. If any systems listen specifically for LocalPosition, they may miss the change.
Apply (assuming LocalPosition exists on TransformModifyFlags):
protected override _decomposeLocalMatrix(matrix: Matrix, pos: Vector3, quat: Quaternion, scale: Vector3): void { matrix.decompose(pos, quat, scale); this._updatePositionByAlignment(); + this._setDirtyFlagTrue(TransformModifyFlags.LocalPosition); this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler | TransformModifyFlags.LocalMatrix); this._setDirtyFlagFalse(TransformModifyFlags.LocalQuat); }If LocalPosition isn’t a defined flag, call
super._onPositionChanged()after updating the position instead.
258-263: Redundant WorldPosition dirty toggle
super._onWorldPositionChanged()already handles world-position dirtiness. The extra flag set may be redundant.Apply:
protected override _onWorldPositionChanged(): void { super._onWorldPositionChanged(); - if (!!this._horizontalAlignment || !!this._verticalAlignment) { - this._setDirtyFlagTrue(TransformModifyFlags.WorldPosition); - } }
311-317: Doc phrasing: “greater than 0” → “non-negative”You clamp to zero, so zero is valid. Adjust the comment.
Apply:
- // The values of size must be greater than 0. + // The values of size must be non-negative.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.ts
🧬 Code graph analysis (1)
packages/ui/src/component/UITransform.ts (2)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 2/4)
- GitHub Check: codecov
🔇 Additional comments (5)
packages/ui/src/component/UITransform.ts (5)
227-230: Parent-change hook may miss base invariants_UITransform._parentChange() doesn’t call
super._parentChange(). If core Transform relies on this hook to update caches/flags, skipping it risks inconsistent world state.Consider:
_parentChange(): void { - this._isParentDirty = true; - this._updateWorldFlagWithParentRectChange(TransformModifyFlags.WmWpWeWqWsWus); + // Preserve base invariants. + // @ts-ignore + super._parentChange?.(); + this._isParentDirty = true; + this._updateWorldFlagWithParentRectChange(TransformModifyFlags.WmWpWeWqWsWus); }Please confirm whether core Transform defines
_parentChange()and if it must be invoked.
265-303: Nice: alignment math is correct and side-effect safeFormulas for Left/Center/Right and Top/Middle/Bottom are correct, and temporary callback detachment avoids re-entrancy. LGTM.
89-136: Insets setters behave correctly under flagsBitwise checks and conditional size recompute on stretch are sound; finite-guard avoids NaNs/Infinity. LGTM.
Also applies to: 163-209
398-405: Enum surface looks goodUI-only flags are separate and dispatched appropriately. LGTM.
247-249: Verify rotation/scale propagation under UI alignment
Overriding_onWorldMatrixChangeskips thesupercall when eitherhorizontalAlignmentorverticalAlignmentis set. Confirm that parent rotations and scales still propagate into the child’s worldQuaternion/scale—add a test that rotates/scales a parent while a child has alignment enabled and assert the child’s world transform updates accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ui/src/component/UITransform.ts (1)
232-238: Clone loses alignment config and insets; copy them in _cloneTo.Cloned UITransforms won’t preserve alignment mode or offsets, leading to different layout after cloning.
override _cloneTo(target: UITransform, srcRoot: Entity, targetRoot: Entity): void { // @ts-ignore super._cloneTo(target, srcRoot, targetRoot); target.size.copyFrom(this._size); target.pivot.copyFrom(this._pivot); + // Preserve alignment configuration and insets. + target._horizontalAlignment = this._horizontalAlignment; + target._verticalAlignment = this._verticalAlignment; + target._alignLeft = this._alignLeft; + target._alignRight = this._alignRight; + target._alignCenter = this._alignCenter; + target._alignTop = this._alignTop; + target._alignBottom = this._alignBottom; + target._alignMiddle = this._alignMiddle; + // Recompute rect for cloned pivot/size. + target._updateRectByPivot(); }
♻️ Duplicate comments (2)
packages/ui/src/component/UITransform.ts (2)
330-337: Relative layout priority over absolute is correctly enforced.Stretch realigns size on change, aligning with the established behavior for this component.
330-342: Clamp size for non-stretch paths to avoid negative dimensions.Direct size edits can go negative and break rect/placement math; clamp before recalculating rect.
private _onSizeChanged(): void { if ( this._horizontalAlignment === HorizontalAlignmentMode.LeftAndRight || this._verticalAlignment === VerticalAlignmentMode.TopAndBottom ) { this._updateSizeByAlignment(); } + // Clamp explicit size in all cases. + const size = this._size; + // @ts-ignore + const prev = size._onValueChanged; + // @ts-ignore + size._onValueChanged = null; + size.x = Math.max(0, size.x); + size.y = Math.max(0, size.y); + // @ts-ignore + size._onValueChanged = prev; this._updateRectByPivot(); this._updateWorldFlagWithSelfRectChange(); // @ts-ignore this._entity._updateFlagManager.dispatch(UITransformModifyFlags.Size); }
🧹 Nitpick comments (3)
packages/ui/src/component/UITransform.ts (3)
311-317: Tweak comment: “greater than 0” → “non-negative”.Matches the Math.max(..., 0) behavior.
- // The values of size must be greater than 0. + // Size must be non-negative.
352-364: Skip child propagation when no flags changed.Avoids no-op traversals when worldFlags is 0.
- const children = this.entity.children; - for (let i = 0, n = children.length; i < n; i++) { - (children[i].transform as UITransform)?._updateWorldFlagWithParentRectChange?.(worldFlags); - } + if (worldFlags) { + const children = this.entity.children; + for (let i = 0, n = children.length; i < n; i++) { + (children[i].transform as UITransform)?._updateWorldFlagWithParentRectChange?.(worldFlags); + } + }
258-263: Possible redundant WorldPosition dirty flag.If super already sets WorldPosition, this extra set is unnecessary. Keep if alignment path bypasses core updates; otherwise remove.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.ts
🧬 Code graph analysis (1)
packages/ui/src/component/UITransform.ts (4)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/index.ts (2)
Entity(11-11)TransformModifyFlags(17-17)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)packages/core/src/Transform.ts (2)
position(61-63)position(65-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e (22.x, 1/4)
- GitHub Check: e2e (22.x, 4/4)
- GitHub Check: e2e (22.x, 3/4)
- GitHub Check: codecov
🔇 Additional comments (5)
packages/ui/src/component/UITransform.ts (5)
63-88: Alignment setter side effects look right.Switching modes updates position and stretches update size as expected.
Also applies to: 144-161
265-303: Alignment formulas (Left/Center/Right, Top/Middle/Bottom) look correct.Center uses parent/child centers; edges use rect edges plus insets. TopAndBottom shares Bottom for Y-position, which is reasonable with stretch. If a different anchor is intended, confirm.
305-321: Stretch size calculation and clamping LGTM.Non-negative enforcement via Math.max is correct.
247-255: Recursion guard in _onPositionChanged is correct.Temporarily disabling Vector3._onValueChanged avoids re-entrancy.
240-245: Resolve: UITransform dirty-flag logic is correct
The override must re-dirty LocalMatrix (due to_updatePositionByAlignment) while flagging LocalEuler and clearing LocalQuat. This intentionally diverges from core to handle alignment—no change needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/Transform.ts (1)
306-315: Guard parent inverse in worldMatrix→local mapping
Matrix.invertcan fail (non-invertible parent.worldMatrix). Use the return value and fall back gracefully to avoid propagating invalid locals.Apply:
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat42); - Matrix.multiply(Transform._tempMat42, value, this._localMatrix); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat42); + if (inv) { + Matrix.multiply(inv, value, this._localMatrix); + } else { + // Parent not invertible; treat provided world as local. + this._localMatrix.copyFrom(value); + } + } else { this._localMatrix.copyFrom(value); } - this.localMatrix = this._localMatrix; - this._onWorldMatrixChange(); + this.localMatrix = this._localMatrix; + this._onWorldMatrixChange();
♻️ Duplicate comments (1)
packages/core/src/Transform.ts (1)
637-654: Also guard inverse in worldPosition write path (repeat)Same singular-parent risk when mapping world→local in
_onWorldPositionChanged. Guard the invert and fall back to copying world→local.Apply:
- if (parent) { - Matrix.invert(parent.worldMatrix, Transform._tempMat41); - Vector3.transformCoordinate(worldPosition, Transform._tempMat41, this._position); - } else { + if (parent) { + const inv = Matrix.invert(parent.worldMatrix, Transform._tempMat41); + if (inv) { + Vector3.transformCoordinate(worldPosition, inv, this._position); + } else { + // Parent not invertible; treat as root. + this._position.copyFrom(worldPosition); + } + } else { this._position.copyFrom(worldPosition); }
🧹 Nitpick comments (1)
packages/core/src/Transform.ts (1)
611-615: Avoid dispatching zero dirty-flagsSkip dispatch when
dispatchFlags === 0to prevent redundant notifications.Apply:
- const dispatchFlags = type & ~this._dirtyFlag; - this._dirtyFlag |= type; - this._entity._updateFlagManager.dispatch(dispatchFlags); + const dispatchFlags = type & ~this._dirtyFlag; + this._dirtyFlag |= type; + if (dispatchFlags !== 0) { + this._entity._updateFlagManager.dispatch(dispatchFlags); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/core/src/Transform.ts(5 hunks)packages/ui/src/component/UITransform.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
📚 Learning: 2025-08-26T08:22:31.028Z
Learnt from: cptbtptpbcptdtptp
PR: galacean/engine#2760
File: packages/ui/src/component/UITransform.ts:0-0
Timestamp: 2025-08-26T08:22:31.028Z
Learning: In UITransform, when there is a relative layout (alignment-based positioning), it has higher priority than absolute layout (direct position setting). This means that setting position directly while alignment is active should be overridden by the alignment calculations, which is the intended behavior.
Applied to files:
packages/ui/src/component/UITransform.tspackages/core/src/Transform.ts
🧬 Code graph analysis (2)
packages/ui/src/component/UITransform.ts (3)
packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)packages/core/src/index.ts (2)
Entity(11-11)TransformModifyFlags(17-17)packages/core/src/Entity.ts (2)
Entity(21-830)children(212-214)
packages/core/src/Transform.ts (5)
packages/physics-lite/src/LiteTransform.ts (6)
position(36-38)position(40-46)rotationQuaternion(52-63)rotationQuaternion(65-72)scale(110-112)scale(114-120)packages/math/src/Matrix.ts (4)
rotationQuaternion(206-242)scale(670-694)scale(1166-1169)Matrix(11-1288)packages/math/src/Vector3.ts (3)
scale(207-212)scale(483-489)Vector3(11-612)packages/core/src/Entity.ts (3)
parent(201-203)parent(205-207)transform(155-157)packages/core/src/clone/CloneManager.ts (1)
ignoreClone(9-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: e2e (22.x, 4/4)
🔇 Additional comments (14)
packages/ui/src/component/UITransform.ts (10)
1-12: Well-organized imports support new alignment features.The imports cleanly bring in the necessary core components (TransformModifyFlags, Rect, MathUtil) and the new alignment enums, providing the foundation for the relative layout functionality.
22-32: Good state organization for alignment system.The new private fields provide a comprehensive alignment state management system:
_rectfor local rectangle calculations- Inset values for each alignment direction
- Alignment mode tracking for both axes
60-83: Excellent alignment setter design with proper cascading.The horizontal alignment setter correctly triggers position recalculation for all alignment modes and additionally triggers size recalculation for stretch mode (LeftAndRight), ensuring the layout system remains consistent.
85-204: Well-designed inset properties with smart invalidation.The alignment inset properties (alignLeft, alignRight, etc.) have proper validation, change detection, and conditional updates based on the current alignment mode. The bitwise checks ensure updates only occur when the specific alignment is active.
209-225: Proper lifecycle integration.The constructor properly binds the new event handlers and the
_parentChange()method correctly integrates with the core Transform's parent management system, ensuring alignment-based layouts respond to hierarchy changes.
235-295: Smart override strategy preserves core functionality.The overridden protected methods use conditional logic to only modify behavior when alignment is active, preserving the base Transform behavior for non-aligned elements. The position recalculation logic in
_updatePositionByAlignment()correctly handles all alignment modes.
297-320: Robust size calculation with safety measures.The
_updateSizeByAlignment()method properly handles stretch modes and includesMath.max(..., 0)to prevent negative sizes, which addresses a critical edge case for constrained layouts.
322-356: Excellent change propagation system.The size and pivot change handlers properly cascade updates through the alignment system and world flag propagation, ensuring that rect changes correctly trigger downstream layout updates in child elements.
358-386: Sophisticated hierarchical update logic.The
_updateWorldFlagWithParentRectChange()method implements a well-thought-out cascading system that:
- Handles both self-initiated and parent-initiated changes
- Correctly manages stretch layout recalculations
- Properly propagates flags through the hierarchy
- Avoids redundant updates through dirty flag checks
393-396: Clean flag extension.The UITransformModifyFlags enum appropriately extends the core transform flags with UI-specific Size and Pivot flags, maintaining the established pattern from the core Transform system.
packages/core/src/Transform.ts (4)
53-53: Good: expose parent-dirty for subclassesMaking
_isParentDirtyprotected enables UI components (e.g., UITransform) to invalidate cached parents safely.
589-593: Nice: local-matrix change hook + explicit world-matrix clearLightweight, targeted hooks; good extension points for higher-level layout systems.
617-635: Parent-transform cache looks solidLookup + cache invalidation via
_isParentDirtyis straightforward and safe.
878-878: Doc tweak acknowledgedThe clarified comment for TransformModifyFlags reads well.
| value.decompose(position, rotationQuaternion, scale); | ||
| this._onLocalMatrixChanging?.(); | ||
| this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler); | ||
| this._setDirtyFlagFalse(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle Matrix.decompose() failure to avoid corrupt local state
Matrix.decompose(...) returns boolean; ignoring a false result can leave position/rotation/scale inconsistent (NaNs/garbage). Add a guard and a safe fallback.
Apply:
- value.decompose(position, rotationQuaternion, scale);
- this._onLocalMatrixChanging?.();
- this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler);
- this._setDirtyFlagFalse(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat);
+ const ok = value.decompose(position, rotationQuaternion, scale);
+ this._onLocalMatrixChanging?.();
+ if (!ok) {
+ // Fallback: extract translation; reset rotation to identity and scale to 1s.
+ value.getTranslation(position);
+ rotationQuaternion.set(0, 0, 0, 1);
+ scale.set(1, 1, 1);
+ }
+ this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler);
+ this._setDirtyFlagFalse(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| value.decompose(position, rotationQuaternion, scale); | |
| this._onLocalMatrixChanging?.(); | |
| this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler); | |
| this._setDirtyFlagFalse(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat); | |
| const ok = value.decompose(position, rotationQuaternion, scale); | |
| this._onLocalMatrixChanging?.(); | |
| if (!ok) { | |
| // Fallback: extract translation; reset rotation to identity and scale to defaults. | |
| value.getTranslation(position); | |
| rotationQuaternion.set(0, 0, 0, 1); | |
| scale.set(1, 1, 1); | |
| } | |
| this._setDirtyFlagTrue(TransformModifyFlags.LocalEuler); | |
| this._setDirtyFlagFalse(TransformModifyFlags.LocalMatrix | TransformModifyFlags.LocalQuat); |
🤖 Prompt for AI Agents
In packages/core/src/Transform.ts around lines 265-269, Matrix.decompose(...)
return value is ignored which can leave position/rotation/scale with NaNs on
failure; change the code to check the boolean result and only apply the
dirty-flag logic when decompose succeeds. On failure, restore previous
position/rotationQuaternion/scale (capture them before calling decompose) or set
safe defaults (position = zero, rotationQuaternion = identity, scale =
Vector3.One), and avoid marking LocalEuler as dirty while clearing
LocalMatrix|LocalQuat as appropriate; optionally log or warn about the decompose
failure for debugging.
Please check if the PR fulfills these requirements
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
What is the current behavior? (You can also link to an open issue here)
What is the new behavior (if this is a feature change)?
Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)
Other information:
Summary by CodeRabbit
New Features
Refactor
Tests