Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This project follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.

### Fixed

- **A multi-line `className` hid its flex tokens from the row and column composers, and this project's own style guide is what put them there.** `.claude/rules/widgets.md` and `SKILL.md` both instruct a className covering 3+ concerns to be a triple-quoted string with one concern per line, so `flex-1` at the end of a line arrives at the composition helpers as `flex-1\n`. Three of them split on a single space and therefore never matched it. Two consequences, both reproduced: a `flex-1` child of an `overflow-hidden` row got wrapped a second time and threw `Incorrect use of ParentDataWidget` (`_selfWrapsInFlex`), and a `w-24 shrink-0` child in a crowded row shrank to its 50pt flex share instead of holding 96pt (`_hasShrinkZero`). The third site, `_hasExplicitCrossWidth`, is corrected for consistency with its own documented "in ANY state or breakpoint variant" intent, but no observable failure could be produced for it: a stretched column child still renders at the width it asked for, so the miss costs a redundant wrapper rather than a wrong layout. All five token scans in `WDiv` now share one hoisted `_whitespaceRegex`, which also stops the two that already split on whitespace from allocating a fresh `RegExp` on every pass through the composition path. (`lib/src/widgets/w_div.dart`, `test/widgets/w_div/multiline_classname_test.dart`)
- **A multi-line `className` hid its flex tokens from the row and column composers, and this project's own style guide is what put them there.** `.claude/rules/widgets.md` and `SKILL.md` both instruct a className covering 3+ concerns to be a triple-quoted string with one concern per line, so `flex-1` at the end of a line arrives at the composition helpers as `flex-1\n`. Three of them split on a single space and therefore never matched it. Two consequences, both reproduced: a `flex-1` child of an `overflow-hidden` row got wrapped a second time and threw `Incorrect use of ParentDataWidget` (`_selfWrapsInFlex`), and a `w-24 shrink-0` child in a crowded row shrank to its 50pt flex share instead of holding 96pt (`_hasShrinkZero`). The third site, `_hasExplicitCrossWidth`, never missed at all and is changed only so all five scans tokenize the same way: it matches with `startsWith('w-')` rather than equality, and `'w-24\n'.startsWith('w-')` is true, so a trailing newline never hid an explicit width from it. That is also the real reason a test written for it passed before the fix, and the reason it ships without one. All five token scans in `WDiv` now share one hoisted `_whitespaceRegex`, which also stops the two that already split on whitespace from allocating a fresh `RegExp` on every pass through the composition path. (`lib/src/widgets/w_div.dart`, `test/widgets/w_div/multiline_classname_test.dart`)

- **Every hoverable `WDiv` announced itself as a button that cannot be pressed.** `WDiv` auto-wraps into a `WAnchor` whenever its className carries `hover:`, `focus:` or `active:`, purely to get the state this widget tracks, and `WAnchor` published `Semantics(button: true)` unconditionally: with no gesture behind it. So a decorative card styled `hover:bg-slate-100` reached assistive technology as a control. Measured on `WDiv(className: 'px-4 py-3 hover:bg-slate-100', child: WText('Latency'))`: one button node labelled `Latency` whose action set was `focus` alone, with no `tap`. A screen reader offers it as a button, the user activates it, and nothing happens, because there is no gesture in the tree to run. A gestureless, UNLABELLED `WAnchor` now publishes no semantics node of its own and lets its descendants speak, which is what a state propagator should do (an explicit `semanticLabel` still publishes the named node either way, which is how a disabled control reports that it exists and is unavailable; `WDiv`'s auto-wrap never passes one): the same card keeps its `Latency` label and loses the role. An anchor with `onTap`, `onLongPress` or `onDoubleTap` is unchanged, so `WButton` and every real control keep their single named button node with its tap action, and an explicit `semanticLabel` still wins for the icon-only case that has no child text to merge. One claim to retire with this: the nesting `WAnchor(onTap:) > WDiv(hover:...)` did NOT announce twice, though it published two button nodes in the widget tree. The inner one carried `isMergedIntoParent`, so Flutter folded it into the real tap surface and never sent it to the platform. A reading that counts raw tree nodes rather than platform nodes will report a duplicate announcement that no screen reader ever made. `MergeSemantics` goes with the role rather than staying, and that was measured too: keeping it made a gestureless wrapper ABSORB a descendant control's role and actions, so a locked region tile in a consumer app swallowed the display-only `WCheckbox` inside it and published itself as "US West, button" carrying the checkbox's tap. That is the same bogus claim in a new place, so a styling-only wrapper now publishes nothing at all. (`lib/src/widgets/w_anchor.dart`, `doc/widgets/w-anchor.md`, `doc/widgets/w-div.md`, `skills/wind-ui/SKILL.md`, `skills/wind-ui/references/widgets.md`)

Expand Down
Loading