You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
WAnchor.trackFocus. Defaults to true; false drops the Focus node of a gestureless anchor. Ignored when the anchor has a gesture. (lib/src/widgets/w_anchor.dart, doc/widgets/w-anchor.md)
WindPerfCounters.recordInheritedRead takes a WindInheritedRead enum value instead of a free string. The four keys (mediaQuerySize, mediaQueryBrightness, windTheme, defaultTextStyle) were previously any String, so a typo at a call site would silently sit outside the pinned four and never show up in stats(). The stats map keys are unchanged: the enum serializes through .name. (lib/src/utils/wind_perf_counters.dart, lib/src/widgets/w_text.dart, lib/src/widgets/w_icon.dart, lib/src/widgets/w_svg.dart, lib/src/widgets/w_input.dart, lib/src/widgets/w_div.dart, lib/src/parser/wind_context.dart, test/utils/wind_perf_counters_test.dart)
WindPerfCounters gains widgetBuilds, wrapperEmissions and inheritedReads. The existing six counters (cacheHits, cacheMisses, cacheBypasses, cacheSize, wDivBuilds, wTextBuilds) answered "how much did the style cache do" and "how many WDiv/WText builds ran", but nothing counted every OTHER W-widget's builds, the Flutter (or Wind-authored render-layer) wrapper widgets Wind inserts around content (Container, Padding, MouseRegion, Semantics, DefaultTextStyle, ...), or the four inherited-widget reads on the hot path (mediaQuerySize, mediaQueryBrightness, windTheme, defaultTextStyle). widgetBuilds and wrapperEmissions are Map<String, int> keyed by type name; inheritedReads is fixed to the four keys above. Every increment is one inline call next to the emission or the read it counts, behind the existing enabled flag, so a disabled counter still costs one bool check and nothing is added, removed or reordered in the widget tree. Wind.installPerfResolver() publishes all nine keys through WindDebugRegistry.currentPerf?.stats(). (lib/src/utils/wind_perf_counters.dart, lib/src/wind_facade.dart, lib/src/widgets/*.dart, test/utils/wind_perf_counters_test.dart, doc/core-concepts/debugging.md, skills/wind-ui/)
Wind.installDebugResolver() / Wind.installPerfResolver() widen from kDebugMode to !kReleaseMode. A profile build (flutter run --profile) now carries both resolvers, so a performance measurement session can run against a build that is actually representative of production timing; release still tree-shakes both. The debug resolver suspends WindPerfCounters while it resolves a widget, so a diagnostic snapshot taken during a measurement session adds nothing to inheritedReads or the cache counters. (lib/src/wind_facade.dart, test/wind_facade_test.dart)
Changed
A WDiv whose only state classes are hover: or active: is no longer a Tab or D-pad stop, and its wrapper builds no Focus. Its auto-wrapped WAnchor installed a focus node for every interactive className, so a hover-only row was a keyboard stop that lit nothing and paid for a node attachment plus a Semantics(focusable:) on every build; a consumer's dashboard carried about 193 of them among 399 anchors per frame. WDiv now passes trackFocus: className.contains('focus:'). A focus: div keeps its node and stop exactly as before, focus-within still lights a ring through a hover-only div in between (the ring's own node covers descendants), and primary focus chained from an anchor above still passes through, because it travels in WindAnchorStateProvider, which stays unconditional with MouseRegion. Gesture anchors are untouched. What the hover-only div stops doing is publishing focus-within to its own children: a sibling label with a focus: class, as in WDiv('hover:bg-gray-50', children: [WText('Email', className: 'focus:text-blue-600'), WInput(...)]), used to light through the div's node while the field had focus and now stays unlit; adding any focus: class to the row brings the node back. A className string cannot see what its descendants style, so gating on them was not an option. (lib/src/widgets/w_anchor.dart, lib/src/widgets/w_div.dart, test/widgets/w_anchor/dpad_activation_test.dart)
WDiv builds its decorated box from primitives instead of a Container.Container is a StatelessWidget that only stacks Align, Padding, DecoratedBox and ConstrainedBox, so it cost one element per decorated div on the hottest path (1032 per painted frame on the same dashboard). The primitives follow Container.build's order and its three behaviours: a childless box expands through LimitedBox, padding is inset by the border widths, and w-full tightens the constraints so max-w-* still clamps it. A zero Padding, which Container emitted for every borderless decoration, is skipped. Geometry is pinned by tester.getSize cases written against the old Container first; AnimatedContainer and the inside-the-border clip are unchanged. wrapperEmissions now counts DecoratedBox, ConstrainedBox, Padding, Align and LimitedBox where it counted Container. Tests that read decoration off find.byType(Container) now read it off DecoratedBox. (lib/src/widgets/w_div.dart, test/widgets/w_div/sizing_test.dart, test/utils/wind_perf_counters_test.dart)
WindContext.build and the h-full fallback depend on MediaQuery.sizeOf, not the whole MediaQueryData. Every parse subscribed every W-widget to all of MediaQuery, so each frame of a keyboard inset animation rebuilt every styled widget on screen. The size aspect still carries both axes, which w-screen / h-screen need, so widthOf would not do. A viewInsets change no longer rebuilds a plain WDiv; a size change still does. wScreenIs and wScreenCurrent read the same aspect, so a shell that swaps its tree on wScreenIs(context, 'lg') no longer rebuilds on every keyboard frame, and WPopover / WSelect's flip checks do too. (lib/src/parser/wind_context.dart, lib/src/widgets/w_div.dart, lib/src/utils/wind_helpers.dart, lib/src/widgets/w_popover.dart, lib/src/widgets/w_select.dart, test/parser/wind_context_test.dart, test/utils/wind_helpers_test.dart)
The contracts floor names this batch's release.fluttersdk_wind_diagnostics_contracts moves ^1.1.0 to ^1.2.0, the release that documents the widgetBuilds, wrapperEmissions and inheritedReads keys this version publishes. The old range already admitted 1.2.0, so a fresh pub get resolves nothing differently. (pubspec.yaml)
Fixed
WindPerfCounters.inheritedReads now counts the windTheme and mediaQuerySize reads WindContext.build makes on every WindParser.parse, not only the ones WInput and the h-full paths already recorded.WindContext.build (lib/src/parser/wind_context.dart:70-71) calls WindTheme.dataOf(context) and MediaQuery.of(context).size on every W-widget build, but before this fix only WInput's brightness fallback and WDiv's h-full render-layer box called recordInheritedRead, so a plain WDiv/WText build under-reported both keys. (lib/src/parser/wind_context.dart, test/utils/wind_perf_counters_test.dart)