fix(web_core): derive the active tab index instead of writing it in willUpdate - #2647
josemontespg wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the update lifecycle of A2UI Lit elements by replacing the update override with a shouldUpdate override to gate the update cycle on the element being bound to a controller. This ensures that the controller is guaranteed to be present during rendering and updates, allowing the removal of optional chaining (?.) on this.controller across various components and documentation. Additionally, the Tabs component was updated to clamp the active index during render rather than mutating it in willUpdate. New tests were added to verify element updates without a context and to ensure correct behavior when the tabs array shrinks. There are no review comments, so I have no feedback to provide.
9111c9f to
6d72160
Compare
6d72160 to
4ef3bdc
Compare
…illUpdate Tabs.willUpdate read this.controller.props to reset activeIndex when the tabs array shrinks. Resetting a @State() field during the update cycle is a side effect standing in for a derivation: it schedules a second pass and silently discards a selection the user may still hold if the array grows back. It also ran before the base class binds the controller, so mounting <a2ui-tabs> before a context was attached threw. Clamp in render() instead, where the controller is guaranteed and where the value is recomputed per render rather than stored. With the controller guaranteed after binding, the remaining this.controller?. reads in the basic catalog no longer describe a state that can occur. Removing them means a missing controller fails at the read rather than rendering an empty component with no explanation.
4ef3bdc to
f69b9e5
Compare
Summary
Updates the
Tabscomponent to derive its active tab index dynamically duringrender()rather than mutating@state()inwillUpdate(), and removes defensive optional chaining onthis.controlleracross the basic catalog.Problem
The
Tabscomponent previously usedwillUpdate()to clampthis.activeIndexwhenever the number of available tabs changed:This pattern caused several issues:
@state()property insidewillUpdate()requests an additional update pass from Lit.this.activeIndexpermanently erased the user's selection. If a tabs array temporarily shrunk (such as during dynamic data filtering) and later restored its items, the user's tab selection was lost.willUpdate()ran beforethis.controllerwas instantiated, readingthis.controller.propsthrew aTypeErrorif<a2ui-tabs>was rendered before being bound to a context.this.controller?.props. Becausethis.controlleris guaranteed once an element updates, optional chaining masked programming errors and allowed components to silently render blank UI instead of surfacing an issue.Solution
render():Remove
willUpdate()entirely fromTabs.ts. Inrender(), compute the clamped index as a local derived value:Replace
this.controller?.propswiththis.controller.propsinBasicCatalogA2uiLitElementandChoicePicker. A missing controller now surfaces immediately at the access point rather than silently producing empty markup.Verification
Tabs.test.ts:<a2ui-tabs>can mount without a context without throwing an error.this.activeIndex, the rendered content falls back to the first tab while preserving the user's selection inthis.activeIndex.yarn --cwd renderers/web_core testpasses (545 tests).Pre-launch Checklist