fluent_2 0.0.3
fluent_2: ^0.0.3 copied to clipboard
Microsoft Fluent 2 components for Flutter web and desktop: 90+ widgets, 20 chart types, tokens, theming, a11y and 135 locales. No Material.
0.0.3 #
Changed #
- BREAKING:
FluentRadioGroupScopeno longer carriesvalueoronChanged. Selection now travels through the framework'sRadioGroup<T>/RadioGroupRegistryinstead, so the scope keeps onlydisabledandlabelPosition. Code constructing or reading the scope directly breaks at compile time; code usingFluentRadioGroupandFluentRadiois unaffected. FluentRadio<T>is now aStatefulWidget. Its constructor is unchanged, so ordinary callers are unaffected — only subclasses andis StatelessWidgetchecks break.- Two radios sharing one value in a group now assert. The framework's
RadioGroupPolicyrejects it ("can't be used for a radio group that allows multiple selection") where it previously just painted two checked dots. That is a caller bug the framework is now diagnosing; suppressing it would mean not registering with the group at all. - A determinate
FluentProgressBarannounces50, not50%. The role requires a parseable number: at the declared floor of Flutter 3.41 the framework's owndouble.parsethrows aFlutterErroron a trailing%(3.47 later relaxed this). TheprogressBarrole plus the newminValue/maxValueis what makes a screen reader say "percent"; upstream Flutter's ownProgressIndicatoremits a bare number for the same reason. FluentPopoverArrowPaintertakes atextDirection. The painter drew a fixed physical apex whilebuildFluentPopoverlays its arrow out with a direction-awareRow, so in an RTL subtree the arrow appeared on the wrong edge, pointing into its own surface. PassDirectionality.of(context). Optional, defaulting toTextDirection.ltr— which is precisely the behaviour the painter had before the field existed, so this is not a breaking change and callers that omit it are unaffected.
Fixed #
- Every popup swallowed the click, hover and scroll behind it. All seven —
FluentPopover,FluentMenu,FluentDropdown,FluentTagPicker,FluentTimePicker,FluentDatePickerandFluentBreadcrumb's overflow — painted an opaque full-screenPositioned.fillbarrier to catch outside taps. It caught everything else too: a button behind an open popup needed two clicks, hover never reached it, and the page could not be scrolled. Dismissal is now aTapRegiongroup, matching upstream's document-leveluseOnClickOutside— the click dismisses and lands. Two consequences worth knowing: aTapRegionSurfaceancestor is required, whichWidgetsApp(and soFluentApp) provides but a bareOverlaydoes not; and on touch or trackpad a drag-scroll now dismisses, becauseRenderTapRegionSurfacedoes not take part in gesture disambiguation. Mouse wheel is unaffected. - A popover opened from inside another popover collapsed the chain. The
inner surface lives in its own
OverlayEntry, so it fell outside the outer popover's tap group and merely opening it read as an outside tap. Nested popups now share one group viaFluentTapGroup. - Closing a popover no longer steals focus from the control an outside tap
just landed on — it restores to the trigger only when the popover itself held
focus, the rule
FluentDatePickeralready documented. - A
FluentSwitchinside aFluentFieldrendered a stretched track. With no label the switch's content was a bareSizedBox.fromSize, andFluentFieldlays its children out withCrossAxisAlignment.stretch(deliberately, matching upstream'sdisplay: gridroot) — so a tight width constraint forced the 40x20 track to the full field width, measured at 584px on the Field page's component example. Upstream's switch root isdisplay: inline-flexand never stretches, so the switch now always wraps in amainAxisSize: minrow, exactly asFluentCheckboxalready did. FluentSwatchPickerwas N tab stops with dead arrow keys, while telling assistive technology it was a mutually-exclusive group. It now has a roving tabindex: one tab stop, arrows move within it. The arrow model follows upstream'suseArrowNavigationGroup— a row wraps on all four arrows; a grid steps Left/Right across row boundaries and wraps, moves Up/Down by row without wrapping, and Home/End reach the ends of the current row.- An open popup no longer keeps a stale height when the page scrolls under
it.
FluentDropdown,FluentTagPicker,FluentTimePicker,FluentDatePicker,FluentInfoButton,FluentBreadcrumbandFluentMenuall cap their surface at the room left beside the anchor, and nothing re-measured it once open: the surface correctly followed its trigger up the viewport while keeping the height it was given near the bottom. They now re-measure on scroll, matching upstream's reposition-rather-than-close behaviour. Gated onScrollPosition.isScrollingNotifier, so it re-measures at scroll start and stop rather than every frame. FluentRadioGroupwas N tab stops, not one. A radio group is a single composite control: Tab enters it once and arrows move within it. It now adopts the framework'sRadioGroup/RadioClient, which also fixes a group whose selected radio is disabled becoming entirely unreachable by Tab.FluentTabListandFluentListwere N tab stops each, contradicting theSemanticsRole.tab/tabBarthey already declared. Both now use the roving tabindexFluentToolbaralready implemented.- Semantics roles.
FluentDataGridnow exposestable/row/cell/columnHeader;FluentSpinnerloadingSpinner;FluentPresenceBadgeandFluentStatusIndicatorstatus;FluentProgressBarprogressBarwith a range.FluentNav,FluentNavDrawerandFluentBreadcrumbtake thenavigationlandmark role only when given a non-emptysemanticLabel— two unnamed landmarks on one page is a framework assertion, and an unnamed nav beside an unnamed breadcrumb is the ordinary case. - Text controls had no context menu at all.
FluentTextSelectionControlsextendedTextSelectionControlsrather than mixing inTextSelectionHandleControls, soTextSelectionOverlay.showToolbartook the legacybuildToolbarpath — which returned an empty widget — and never consultedEditableText.contextMenuBuilder. Right-click and long-press produced nothing onFluentInput,FluentTextarea,FluentSearchBoxandFluentSpinButton. - A subtree
FluentThemeOverrideno longer leaks out of the text context menu.ContextMenuController.showcaptures inherited themes from inside its ownOverlayEntry.builder, wherefrom:andto:are both already below theNavigator, so the capture came back empty;fluentTextContextMenuBuildernow captures at the call site. FluentNavandFluentToolbarcould become permanently unreachable by Tab. Disabling the row or item holding the roving tab stop left the control with zero tab stops, and no registration event fired to re-park it. The toolbar additionally had to clear the derivedskipTraversalits item latched onto its own node while its gate was shut.FluentDataGridpainted no focus ring on the first cell reached by Tab — the rebuild was gated on the cell having moved, and the cell you enter is always the one already holding the roving index.- Popups no longer open off-screen.
FluentTagPicker,FluentTimePicker,FluentBreadcrumb's overflow,FluentInfoButtonandFluentMenunow clamp to the room actually left beside their anchor and flip to the other side rather than collapsing. A bottom-edgeFluentMenutrigger previously rendered a surface of height zero — focus moved into it, Escape bound to it, and nothing painted. Submenus measured their anchor row's position inside the parent surface and read it as a screen coordinate, overhanging the viewport by exactly the parent's owny. - Open popups no longer go stale.
FluentDropdown,FluentTagPickerandFluentTimePickerrebuild their overlay when a dependency moves, so resizing the window re-measures the maximum height and a theme swap repaints the popup. - RTL.
FluentPopoverimplemented its documented reading-order positioning physically;FluentTooltippicked the wrong side and mirrored its arrow wrongly;FluentCarousel's arrow keys ran opposite to its visible motion and its buttons were pinned to physical edges;FluentRatingpainted, hit-tested and arrow-keyed left-to-right only.Directionalityalso does not cross anOverlayEntryboundary and is now carried explicitly into the popover, dialog, toast and menu overlays. - Leaks and lifecycle. Four
OverlayEntrys were removed without being disposed (FluentDatePicker,FluentTimePicker);FluentDatePickerdisposed itsFocusScopenode before removing the entry that builds under it;FluentTreenever pruned focus nodes for removed items;FluentTabListnever disposed its flipCurvedAnimation;FluentSpinButtonleft a focus listener on its internal node. FluentMenuno longer closes an open submenu on an unrelated rebuild. It compared itsitemslist by identity, which is false for any caller passing a fresh list literal.- A right-click no longer paints the pressed token on every control built on
FluentInteractive. - An overlay
FluentDrawernow hides the page behind it from assistive technology, andFluentBreadcrumb's invisible dismiss scrim no longer appears in the semantics tree as an unlabelled full-screen button. FluentTooltipno longer announces its content twice when asemanticLabelis set.
Publishing #
- Require
fluent_2_core0.0.3.
0.0.2 #
Added #
- ColorPicker.
FluentColorPicker,FluentColorArea,FluentColorSliderandFluentAlphaSlider, ported from@fluentui/react-color-picker-preview, withFluentColorPickerStyle,FluentColorAreaStyleandFluentColorSliderStyle, the three matching*Themewidgets and the usualresolve*State/resolve*Style/build*trio per component. The colour is Flutter's ownHSVColor— no new colour type reaches the API — and a picker publishes it to its children throughFluentColorPickerScope, so all four controls always agree. Controlled only: there is nodefaultColor, because upstream's uncontrolled mode gives each child its own copy of the value and they drift apart on the first drag. A new showroom page covers all eight upstream stories.
Fixed #
FluentSliderno longer loses a touch drag to a scrolling ancestor. It used aGestureDetectorwithonTapDown+onHorizontalDrag*, which does not claim the pointer until the drag slop is exceeded — long enough for a horizontally scrolling parent to win the arena. It now claims at pointer-down through the sameEagerGestureRecognizerpath the colour controls use. Mouse input was never affected, because Flutter leaves mouse out ofScrollBehavior.dragDevices, which is why no test caught it.
Breaking #
- Removed
FluentSpinButtonUnderlinePainter. The spin button's two bottom rules now come from the sharedFluentInputUnderline/FluentInputFocusUnderlinepair, like every other input. The painter drew both withcanvas.drawRect, so they were square and overhung the field's rounded corners; upstream'suseSpinButtonStylesrounds them viaheight: max(2px, borderRadiusMedium)plusclipPath: inset(calc(100% - 2px) 0 0 0).FluentSpinButtonChevronPainteris unaffected. Anyone who subclassed or instantiated the removed painter should use the two widgets instead.
Publishing #
- Use the Fluent 2 project logo as the first pub.dev screenshot and thumbnail.
- Require
fluent_2_coreandfluent_2_fonts_web0.0.2.
0.0.1 #
- Initial release.