-
Notifications
You must be signed in to change notification settings - Fork 93
fix(genui): add missing weight property to Component constructor; default TextField width to 1 when nested in a Row
#603
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
base: main
Are you sure you want to change the base?
Conversation
… default `TextField` `width` to 1 when nested in a `Row`
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.
Code Review
This pull request refactors how component weight is handled, transitioning from passing the entire Component object to buildWeightedChild to directly passing its weight property. This involved updating Column and Row widgets to extract the weight from the component, with Row specifically adding logic to default a TextField's weight to 1 if not explicitly defined. The buildWeightedChild helper function was modified to accept weight directly, and the Component model and SurfaceUpdateTool were extended to parse and store this new weight property, supporting both integer and double values. New tests were added to validate the TextField weighting behavior within Row and the correct parsing of weight values. A review comment identified a performance optimization in the Row widget's templateListWidgetBuilder, suggesting that itemContext.getComponent(componentId) should be hoisted out of the loop to prevent redundant calls and improve performance for large lists.
|
Hey this sounds very good! Can you include a screenshot with some example rendered layouts? |
Added some screenshots. |
jacobsimionato
left a comment
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.
Nice!
| templateListWidgetBuilder: (context, list, componentId, dataBinding) { | ||
| final Component? component = itemContext.getComponent(componentId); | ||
| final int? weight = | ||
| component?.weight ?? (component?.type == 'TextField' ? 1 : null); |
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.
This LGTM as a practical fix for this now! I think we need a more scalable solution long term, to avoid other leaf components having this issue. We should figure out what circumstances this error happens in - is it for any leaf component that has an unbounded max width or height? Maybe we need them to be identifiable somehow. Either way, this is a great first step I think!
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.
Yeah, constraints go down; sizes go up and all that1. Basically any widget that relies on a constraint from their parent to figure out how large they should be. For example, I suspect sliders within rows will fall victim to this exact crash.
Description
Supersedes #588. Fixes #559.
Changes
SurfaceUpdateToolwasn't parsing the value of theweightproperty and passing it to theComponentconstructor for any component it was constructing1. Definition ofweightproperty:genui/packages/genui/lib/src/model/a2ui_schemas.dart
Lines 227 to 230 in 061ba89
Textin Flutter). Since we are dealing with an internal API here that is not suffering from any significant amount of API bloat, this PR opts to makeweightparameter required. The only material drawback of making this parameter required is some extra verbosity in test code, which I personally assign very little importance to.buildWeightedChildno longer has arequired Component? componentparameter and instead has arequired int? weightparameter.componentwas only being read for the weight value anyway, and this refactoring also lets us "override" the weight of acomponent. Continue reading to see why we need this.TextFieldwithout a weight, it will assign it a weight of1. This will prevent the layout-induced crashes we see in GenUI TextField crashes with “InputDecorator unbounded width” when generated using A2UI (Flutter GenUI v0.5.1) #559. However, I call this hacky because 1) Row has to be explicitly aware of another catalog component and treat it specially and 2) this is essentially a concession that many A2UI layouts are doomed to be laid out in noticeably different ways across different renderers (even if you tweaked the common variables like colors and padding to be the same across each of the renderers). I am okay with making this concession for now, especially that different UI frameworks fundamentally compute constraints in differing ways, making this a high-cost (near intractable?) problem to solve. It also isn't clear to me how many software products will really suffer from the problem to a significant degree (e.g. "we need a piece of generated UI to look identical on both our HTML and native Android apps").Screenshots
Created using the repro instructions provided by the parent issue. In this scenario, the agent did not provide any weights for any child elements of rows, so this PR's change prevents a crash by assigning a
weightof1to the text fields.Another example (using simple_chat):
Pre-launch Checklist
///).Footnotes
https://github.com/flutter/genui/blob/061ba8943160894a16ab0ffeaae99b7859e0ac49/packages/genui/lib/src/core/ui_tools.dart#L35-L37 ↩