Skip to content

v0.0.6

Choose a tag to compare

@ascobani ascobani released this 24 Sep 18:59
· 5 commits to main since this release

fluent_2 0.0.6

Added

  • FluentBoxDecoration paints boxShadow the way CSS does — outside the box
    only.
    A BoxDecoration shadow is a blurred copy of the box drawn under
    it, which a transparent box shows as a grey wash (shadow16 darkens the
    inside to about 76%). Upstream shadows unfilled elements routinely, so this is
    the decoration for them; the blur also uses CSS's σ = blur / 2. Everything
    else paints as BoxDecoration. The CarouselNav and Carousel demos use it,
    which is what stopped the CarouselNav card rendering solid grey.

  • Charts:

    • calloutPropsPerDataPoint on FluentHorizontalBarChart and
      FluentDonutChart, spread over the built-in reading as ChartPopover does,
      and legends / enabledWrapLines on FluentHorizontalBarChart
      (upstream's legendProps), whose wrapped rows render each legend's
      annotationBuilder.
    • FluentChartTooltipBox, the box a cut-short axis label shows its whole
      text in on hover or a touch tap.
    • FluentChartPopover.anchorRect, FluentChartPopoverData.isCartesian and
      contentMaxWidth, FluentChartHitRegion.popoverAnchor,
      FluentCartesianChartProps.popoverFollowsPointer and
      FluentYValueHover.shouldDrawBorderBottom.
    • FluentChartHitRegion.hitTest (a mark hovers and clicks as its painted
      shape, a circle as a circle), focusable and followsPointer, and
      FluentCartesianSeriesDelegate.hoveredRegionAt, which names the hovered
      region on the same pointer event the chart hears.
    • FluentCartesianSeriesDelegate.activationAt, consulted on a press that
      hits no region (a line chart uses it to click its stroke), and
      FluentCartesianChart.onFocusedRegionChange, fired as the arrow keys move
      the roving focus index and with null on blur.
    • FluentChartPopoverData.culture (upstream's ChartPopoverProps.culture),
      in which a multi-value popover formats its rows.
    • FluentDonutChart.popoverBuilder, which replaces the popover body for
      the hovered or focused datum (upstream's onRenderCalloutPerDataPoint);
      a null return keeps the default body.
    • FluentLineChart.eventAnnotationStrokeColor, eventAnnotationLabelColor
      and eventAnnotationLabelWidth (upstream's
      eventAnnotationProps.labelWidth, default 105), forwarded to the event
      annotation layer.
    • FluentCartesianChartProps.copyWith(useUTC:).
    • FluentChartImageExporter takes clipHeight, continuationKey and
      continuationX, which the declarative chart's export uses to draw every
      legend and a table's whole grid.
  • Components:

    • FluentSplitButton.menuExpanded and an optional child (an icon-only
      primary half); FluentMenuTriggerScope, through which FluentMenu
      scopes its open state to its trigger so the split button's chevron half
      takes its Selected tokens and announces expanded.
    • FluentFocusRing's inset mode, and FluentButtonStyle.focusRingInsets,
      focusRingInnerColor and shadow (upstream's ring sits inside the
      button; primary adds a white inner ring and shadow2).
    • FluentSpinnerPainter.textDirection (the arc mirrors in RTL),
      FluentSpinnerMotion.reducedRotation, FluentSpinnerPose.reduced and
      tailFades.
    • FluentInputStyle.focusUnderlineWidth, the focus bar's thickness.
    • FluentDatePickerValidationResult.message, the errorStrings (or
      ambient locale) text for the error, for a FluentField to show.
    • FluentCalendarPanel.slideProgress and slideForwards.
    • FluentButton.activeIcon (upstream's bundleIcon filled glyph, shown
      while a subtle or transparent button is hovered or pressed; also on
      FluentCompoundButton) and FluentButton.menuIcon (MenuButton's chevron
      slot: 12, or 16 at large, 4 after the label, in the label colour).
    • FluentButtonStyle.iconColor, menuIconSize and animationDuration.
    • FluentLinkUnderline, which paints a link's underline as a crisp 1px
      line under every line of the label.
    • FluentCarouselNavAppearance, FluentCarousel.navAppearance and
      FluentCarouselStep.appearance (upstream's brand CarouselNav).
    • FluentTreeItem.aside, the always-visible trailing slot.
    • FluentInteractive.disabledMouseCursor and pressedRequiresHover
      (upstream's :hover:active).
    • FluentInteractionTag.activeIcon, the filled glyph an outline tag shows
      while hovered or pressed, and FluentTagStyle.iconColor.

Changed

  • Requires fluent_2_core 0.0.4, which keeps FluentApp's tree when it
    rebuilds after the fonts load and corrects eight palette tokens to Fluent UI
    React v9 (lavender avatars no longer render navy).

  • Chart prop spellings fixed; the old names are deprecated, not removed.
    showXAxisLablesTooltip, wrapXAxisLables, rotateXAxisLables,
    showYAxisLables and showYAxisLablesTooltip on
    FluentCartesianChartProps (and resolveShellXAxisTickPadding's
    parameter) are now *Labels, and xAxistickSize on
    FluentCartesianChartProps and FluentXAxisParams is xAxisTickSize.
    Each old name stays as a @Deprecated constructor argument, getter and
    copyWith argument that forwards to the new one, so 0.0.5 code compiles.

  • Deprecated: FluentChartLegendRow.listLength (now optional; Flutter
    has no aria-setsize semantics to carry it) and
    FluentCartesianChartProps.enableFirstRenderOptimization (the port always
    lays out with real constraints, so there is no first frame to skip). Both
    were already ignored.

  • tickPadding is honoured. A caller's FluentCartesianChartProps .tickPadding used to be read only as a truth test (25 painted a 5 gap, 0
    gave 10), copying a JavaScript precedence slip; it is now
    tickPadding ?? (tooltip ? 5 : 10).

  • Button geometry follows upstream in Chrome (every FluentButton): a
    1px border that takes layout space on every appearance, labelled buttons
    floored at 64/96/96 wide, icon-only buttons a 24/32/40 square with 1/5/7
    padding, the focus ring inside the button, and a menu button's label and
    chevron centred as one group. The legend's "+N more" button grows to the
    floor as well.

  • FluentSplitButton matches upstream: icon-only chevron half (large is
    31 wide, the chevron 1px low as upstream's svg sits), the divider's tokens
    per appearance and state, the open-menu Selected state, a whole-pixel
    seam, and the edges drawn with CSS border geometry — a circular split
    button is now a stadium, not two ellipses, and the outline no longer
    notches at the seam.

  • FluentSpinner moves like react-spinner 9.4+ (two conic wedges behind
    a mask) instead of the old stroke-dasharray keyframes: the arc grows from
    30° to 255° and back with no snap at the cycle boundary, has flat ends,
    and mirrors in RTL. Under reduced motion the ring keeps turning over 1.8s
    with a fixed, fading comet tail, as upstream does, instead of freezing.
    The ring repaints on its own RepaintBoundary.

  • FluentGanttChart's date axis honours useUtc (it built a local time
    scale while the popover read UTC); props.useUTC ?? useUtc now feeds both,
    and only true or 'utc' enable UTC.

  • FluentDataGrid headers and rows follow upstream: a sortable header is
    one interactive surface with the subtle hover and press fill, a bare 12px
    arrow shown only while it holds the sort (an unsorted column draws none,
    keeping an empty slot), and regular-weight labels; a pressed row fills
    subtleBackgroundPressed; a cell's focus ring shows for keyboard focus
    only.

  • Nav rows follow the storybook: labels stay neutralForeground2 in
    every state, a held plain row keeps the hover fill, and split-row
    secondary actions fade in over the row end on hover, press or focus, so
    the label keeps its width.

  • Horizontal bar rows fit their gaps. A row of n bars used to run
    (n − 1) × 3px past its edge (past the start in RTL); bars now shrink into
    the room the gaps leave, and a zero-width bar takes no gap
    (FluentHorizontalBarRowLayout.compute, new absoluteLabelIndex).

  • BREAKING (custom styles): FluentInputStyle.borderWidth,
    bottomBorderColor and bottomBorderWidth now describe a real CSS-style
    border.
    The border takes space and the content row sits inside it, on top
    of padding — the bottom side used to be a rule overlaid on the box's bottom
    edge that cost no layout. A null borderColor means no border and no inset
    whatever borderWidth says; a null bottomBorderColor means the bottom
    follows borderColor. A custom style that set a wide bottom rule, or relied
    on the border not moving the text, will lay out differently. The same holds
    for the bottom-side fields of FluentSearchBoxStyle, FluentTextareaStyle,
    FluentSpinButtonStyle, FluentDropdownStyle, FluentTagPickerStyle,
    FluentDatePickerStyle and FluentTimePickerStyle.

  • BREAKING (sibling APIs), each to match upstream:

    • FluentSpinButtonBaseState.inert is gone — read-only no longer styles the
      surface, only the steppers go inert;
    • FluentSpinButtonChevronPainter no longer takes glyphSize or
      strokeWidth: it fills upstream's 14px svg path;
    • FluentTextarea.maxLines: null holds the field at minLines rows and
      scrolls, as upstream's rows does; pass maxLines to let it grow;
    • FluentTimePickerStyle.trailingGap is now the space between the text
      field and the trailing glyph, and trailingPadding the inset around the
      text field;
    • FluentDropdown and FluentTimePicker take upstream's 250px minimum
      width;
    • FluentTagPicker draws upstream's expand chevron by default (expandIcon,
      fluentTagPickerChevron), is 34/42/46 tall, and has 32px option rows and
      upstream-sized tags;
    • FluentTagDismissPainter.inkRatio is gone: the dismiss glyph fills
      upstream's DismissRegular path instead of a scaled cross;
    • FluentSpinButtonStepper is now a StatefulWidget (it repeats while
      held).
  • FluentTag.media is new — upstream's media slot, for an avatar, 1px
    inside the border; icon stays at the content inset. A FluentTagPicker
    chip puts its avatar there (new FluentTagPickerOption.tagMedia, which
    falls back to media).

  • FluentInputBorderPainter is new and is what paints the border. Where the
    bottom colour differs from the sides, the two meet along each bottom corner's
    diagonal the way a browser joins adjacent border colours, instead of the
    bottom colour stopping a pixel up the arc. Public with its fields, so tests
    read the resolved tones off it, as with FluentRadioIndicatorPainter.

  • The focus bar eases on CSS ease and reverses the way CSS does. Upstream
    writes the curve tokens into transitionDelay — a typo for
    transitionTimingFunction — so every browser drops them and runs ease,
    which the port had been reading as intent and replacing with
    curveDecelerateMid / curveAccelerateMid (45% of the bar drawn 20ms in,
    against upstream's 9.5%). fluentInputFocusUnderlineEnter / Exit are now
    FluentCssCubic.ease — new, a cubic-bezier() solved to 1e-7 as Chromium
    solves it, where Flutter's Cubic stops at 1e-3 and drew the bar's ends up
    to 0.4px off Chrome's — and a focus change mid-flight starts a fresh ease
    from the current scale over the direction's duration times the distance
    left, instead of retracing the old curve. Every field sharing the bar picks
    this up: FluentInput, FluentTextarea, FluentSearchBox,
    FluentDropdown, FluentTagPicker, FluentSpinButton, FluentDatePicker
    and FluentTimePicker, whose alias constants follow.

  • FluentInput matches upstream as rendered in Chrome rather than the Figma
    set
    , and so does FluentDatePicker, which is .fui-Input upstream and
    derives its faceplate from it:

    • a focused outline field keeps neutralStroke1Pressed /
      neutralStrokeAccessiblePressed even while hovered;
    • a read-only FluentInput is styled exactly like rest — it was on the
      disabled ramp;
    • invalid is colorPaletteRedBorder2 (#d13438 light), not
      statusDangerBorder2; high contrast keeps the status token;
    • underline has square corners, on the root and the focus bar;
    • the bottom border stays 1px while pressed — it was 2px;
    • text and slots sit inside the border: 1px further in on outline and filled,
      and 0.5px higher on underline, whose only border is the bottom one;
    • large's text inset is 18 (12 + SNudge), not Figma's 14;
    • the caret is 1px, a browser's width, not EditableText's 2 (also in
      FluentTagPicker, which composes FluentInput).
  • FluentSearchBox, FluentTextarea, FluentSpinButton, FluentDropdown,
    FluentTagPicker and FluentTimePicker match upstream as rendered in
    Chrome
    , each measured across its appearances, sizes and states at a pixel
    ratio of 4:

    • read-only is styled like rest on all of them — it was on the disabled
      ramp;
    • invalid is colorPaletteRedBorder2, with new error parameters on
      FluentSearchBox, FluentDropdown and FluentTagPicker;
    • the bottom border is 1px in every state, joins the sides on the corner
      diagonal and, like the rest of the border, sits outside the content;
    • the caret is 1px, and a disabled field shows not-allowed;
    • focus follows each component's own cascade. SearchBox and SpinButton write
      :active,:focus-within as one rule, so a focused field keeps the Pressed
      stop through a hover, as Input does. Textarea, Dropdown, TagPicker and
      TimePicker write :focus-within alone, which Griffel sorts before
      :hover, so hover wins there; a focused Textarea's bottom border is
      compoundBrandStroke;
    • Textarea is 44/56/68 tall (new FluentTextareaStyle.minimumSize);
      SpinButton's border is drawn over its steppers, whose fills follow the
      appearance; TimePicker follows Combobox's padding and ramp rather than
      Input's, and gained hover and press states; Dropdown's fill no longer
      ramps on hover and press — only Outline's border does, as upstream.
  • FluentDatePicker and FluentTimePicker pass their real readOnly to the
    style resolver.
    They used to hide it so a default, read-only picker did not
    render greyed out; with read-only unstyled there is nothing left to hide.

  • Every text field focuses on mouse-down, as Chrome does, so the focus bar
    grows under a held press.
    Flutter's text gestures focus on tap-down, which
    a middle press never reaches and which waits for the gesture arena whenever
    it is contested: the bar started a whole click late. FluentInput (and so
    FluentTagPicker), FluentTextarea, FluentSearchBox, FluentSpinButton,
    FluentDatePicker, FluentTimePicker and FluentDropdown now focus on a
    mouse press of any button, with the caret where it landed, through the
    field's own selection path so desktop's select-all-on-focus stays out.
    SearchBox focuses only from its <input> box, not the icon or padding, and a
    right press that moves focus there is not :active (Chrome).

  • Behaviour now follows upstream in Chrome:

    • SpinButton steppers step on press and repeat while held (305 / 541 /
      725ms…, within a frame of upstream); a stepper whose value equals its
      bound goes inert — greyed glyph, no fill, not-allowed — and a press
      there takes focus away;
    • TagPicker keeps its field (and focus) when the first tag appears, so
      typing continues after a pick; a printable key reopens the list and
      highlights the first option starting with the text, which Enter adds; the
      list refreshes while typing; a click anywhere on a chip removes it; the
      secondary-action aside stretches to the full height;
    • DatePicker gained hover and press, and shows the hover ramp rather than
      the focused one while the calendar holds focus;
    • a right press shows :active on Input, DatePicker, Textarea, SearchBox and
      SpinButton's text, but not on a live stepper or the Combobox family;
    • Textarea shows touch selection handles for touch only;
    • a disabled field shows not-allowed over its text, and a disabled
      Dropdown over its whole trigger.
  • A fixed parent height stretches every text field, with the focus bar on
    its bottom edge, as CSS height does — it used to draw the box at its
    natural height and the bar below it.

  • BREAKING (behaviour), to match upstream's Combobox family:

    • FluentTagPickerRemoveLastIntent (Backspace in an empty field) focuses
      the last chip instead of removing it; Delete, Backspace, Enter or Space
      (on release) then removes the focused chip;
    • FluentTagPickerStyle.fieldWidth is a minimum (24) rather than a fixed
      96: the field takes the rest of the chips' last line and wraps below it
      or when its text no longer fits; contentPadding changed meaning, and
      tagRunSpacing, tagPadding and fieldSpacing are new;
    • a non-freeform FluentTimePicker takes a caret and typing (type-ahead;
      its text reverts on close or picks an exact match), and
      resolveFluentTimePickerState(readOnly:) defaults to false; hourCycle
      is nullable; the default parser accepts upstream's formats only (8 is
      no longer a time); the 416px surfaceMaxHeight default is gone — the
      list takes the room below the field;
    • FluentInteractive reports pressed for middle and right presses (new
      pressedOnSecondary, which the Dropdown trigger turns off) and tracks
      hover while disabled.
  • Pickers behave as upstream's in Chrome (each measured there first):

    • TimePicker: freeform typing rings the matching option; typed text is kept
      after Tab, blur and Escape instead of being reformatted; Enter with a
      typed match only opens, with none it commits and opens on the committed
      time; Space picks on an open list not being typed into; a chevron press
      toggles on mousedown for any button and leaves the caret; a click that
      drifts still counts; the list keeps its scroll across a reopen;
    • TagPicker: typed text is cleared on blur or close; chips are focusable,
      and a press on one while open removes it and moves focus to the next; a
      click on the field toggles the list (primary button only), and a press on
      the chevron, padding or aside toggles on mousedown; Up opens on the first
      row, disabled rows are visited, and a pick leaves a caller's controller
      alone;
    • Dropdown: PageUp/PageDown move ten rows, Alt+Up selects and closes,
      Alt+Down opens or moves on, keypad Enter commits, and every key but Alt+Up
      reads the same under Shift, Ctrl or Meta; disabled rows are reachable;
      Escape on a shut list reaches a dialog around it;
    • DatePicker: a click while the calendar is open leaves it open unless text
      input is on; with text input the popup keeps focus under a held press and
      the closing click puts the caret where it landed; a press dragged off the
      field opens nothing;
    • lists scroll their active row just into view, 2px clear, instead of
      centring it.
  • FluentField takes upstream's validation colours and glyphs: the message
    and glyph are colorPalette*Foreground1 per state (error #bc2f32), and a
    default glyph is drawn per state (new FluentFieldValidationGlyph) unless
    one is passed. FluentLabel wraps a long label with the required asterisk
    inline after the last word.

  • FluentTooltip.position is now a preference. A tooltip with no room on
    that side opens on the opposite one; see the Positioning section of
    FluentTooltip. buildFluentTooltip is unchanged and still stacks the
    arrow on exactly the side its state names.

  • BREAKING (charts):

    • FluentChartPopoverLayoutDelegate is replaced by FluentChartPopoverLayout
      (and RenderFluentChartPopoverLayout), which places the surface as
      upstream's ChartPopover does: above and centred, flipped, shifted into the
      chart root and height-capped with its body clipped.
    • FluentVerticalBarChartDelegate.barDomain is now
      barDomainFor(FluentCartesianChildContext), and
      FluentScatterChartDelegate.popoverFor returns FluentChartPopoverData?
      (null where no point at that x shows a callout).
    • The HorizontalBar, Donut, Funnel and Polar popovers float in the app's
      Overlay, as upstream's overhang their chart, so hovering one needs an
      Overlay ancestor (FluentApp and WidgetsApp provide it).
    • FluentChartHitRegion.popoverData is nullable: null opens no callout and
      closes an open one, as a mark another legend dims does upstream. A custom
      delegate that reads region.popoverData needs a null check.
  • BREAKING (components), each to match the storybook:

    • FluentDialog.showCloseButton is nullable; null draws the header close
      button on a non-modal dialog only, and the close is a bare 20px glyph;
    • every popover surface lays out its 1px border (2px larger, content 1px
      further in), flips and shifts to stay in the viewport, and
      FluentPopoverStyle.arrowInset defaults to 8;
    • tree item actions show only while the row is hovered, pressed or focused,
      over a 32px row; list items paint no fill; carousel previous, next and
      autoplay are 32x32;
    • compound button padding, type and icon gap follow upstream (60/72/80 high
      with an icon).
  • Charts match the storybook's hover (each measured against the live
    storybook): line, area, scatter, vertical, stacked, grouped and horizontal
    bar charts, donut, gauge, funnel, heat map, gantt, polar, sankey and
    sparkline open, place, follow and close their callouts as upstream does, and
    grow markers and draw hover rules where upstream does.

  • Components match the storybook's hover and press: buttons tween border
    and label colour, subtle icons turn brand on their own, checked toggles
    draw upstream's border and icon, radio labels ramp, nav, tree, data grid,
    list item, breadcrumb and carousel dots follow React's ramps where Figma
    disagreed, and swatch rings keep their white hairline.

  • Disabled controls show not-allowed, and a press dragged off falls back
    to rest, where upstream writes them:

    • FluentInteractive shows not-allowed over a disabled surface by
      default, as Button, Link, menu rows, Tab, Tag (the whole tag),
      InteractionTag, ColorSwatch, AccordionHeader, Card and Breadcrumb do;
      Checkbox, Radio, Switch, Slider, ListItem, listbox options, Calendar, the
      colour pickers, InfoButton, Nav and Tree keep the arrow;
    • Button, CompoundButton, SplitButton, Switch, Radio, ColorSwatch,
      InfoButton, the Calendar's navigation, caption, today and month/year
      cells, menu rows and breadcrumbs are pressed only while the mouse is over
      them, so a press dragged off shows rest and presses again on the way back;
      a touch press holds.
  • Charts answer touch and legends as upstream does: a touch tap hovers
    what it lands on (markers, hover rules and VerticalBarChart's line dots
    included) and a tap outside the chart ends it; a mark another legend dims
    opens no callout and takes no tab stop but still clicks; a LineChart
    segment opens its start point's callout on the move that reaches it; a
    following callout moves only once the pointer has moved more than 1px.

  • More components follow React over Figma:

    • the Tag dismiss glyph (every appearance) and brand InteractionTags ramp
      through colorCompoundBrandForeground1Hover / Pressed;
    • FluentSwatchPicker pads by 0, so its swatches sit flush with the picker
      (they were 10px in);
    • a vertical FluentField pads its label 2px above and below (1px at
      large), so the control starts 26px below the field's top, not 22;
    • FluentCalendar pages with upstream's arrow glyphs instead of chevrons;
    • the hamburger stays transparent and only its glyph ramps, a disabled
      unselected subtle-circular tab is unfilled, and an autoplaying carousel's
      toggle rests checked while it plays.

Fixed

  • Turning reduced motion off again left the focus bar snapping. The bar
    zeroed its durations when MediaQuery.disableAnimations came on and never
    restored them; they are now set on every dependency change.

  • Pressing another field while a FluentDropdown held focus focused
    nothing until release.
    The Dropdown's outside-tap blur ran on the same
    pointer-down and parked focus on the route's scope, cancelling the pressed
    field's own request. It now blurs only if focus is still its own once that
    event has settled, as a click on the page body does.

  • A field removed mid-press threw on the release. FluentInteractive,
    FluentInput, FluentTextarea, FluentSearchBox, FluentSpinButton,
    FluentDatePicker, FluentTimePicker and FluentTagPicker ignore a press
    that ends after they are gone.

  • Hover and press were lost when a field was re-enabled under the mouse.
    FluentDatePicker, FluentTimePicker, FluentTagPicker, FluentTextarea
    and FluentSearchBox track them while disabled and filter them in the
    build, as Chrome keeps a disabled root's :hover and :active.

  • A FluentDropdown whose options shrank under the open list threw on
    Enter; the active row now falls back to the first option.

  • A FluentTooltip near the edge of the window was drawn outside it. The
    surface always sat on the side position named (above by default) and was
    centred on its trigger with no bounds check, so a tooltip on a bar at the
    top of the window landed above the window entirely, and one on a bar's
    end button ran off the side. Upstream's tooltip never pins its placement,
    so usePositioning applies floating-ui's flip and shift to it: the
    surface now flips to the opposite side when the preferred one cannot hold it
    and the opposite one has more room (before/after in reading order), and
    slides along the trigger's edge to stay inside the Overlay. The arrow is
    drawn for the side the surface landed on and stays centred on the trigger,
    8px clear of the surface's corners, the way floating-ui's arrow middleware
    places it. With room on every side nothing moves. It is settled in one
    layout pass — no frame shows the surface on the wrong side, and nothing is
    scheduled while it is open — and the surface still follows a trigger that
    moves.

  • Documented chart and input options that did nothing now work:

    • culture on FluentAreaChart, FluentVerticalBarChart,
      FluentHorizontalBarChartWithAxis and FluentScatterChart localizes
      their readings and tick labels, and the stacked popover of Line, grouped
      and stacked bar charts formats in it (12.345,6 under de-DE);
    • per-point onClick / onDataPointClick handlers run on HeatMap,
      VerticalBar, HorizontalBarWithAxis, Gantt, GroupedVerticalBar, Area and
      Scatter (only Line and stacked bar ran them), and each bar of a
      coalesced grouped-bar stop keeps its own click;
    • FluentLineChartSeries.onLineClick runs when the stroke between markers
      is clicked (markers still win);
    • FluentEventAnnotation.cardBuilder: clicking a label with cards opens
      them in a popover below it, in date order, closed by Escape or an outside
      click;
    • accentWidth on FluentDatePickerStyle and FluentTimePickerStyle sets
      the focus bar's thickness;
    • FluentDatePicker.errorStrings reaches the validation result's
      message.
  • Chart export is sharp and complete. The declarative chart's Download
    captured at pixel ratio 1 and stretched it 5× nearest-neighbour, exported
    only the table rows in view and the "+N more" button instead of the
    legends. It now captures at the export scale (fitted inside the browser's
    8192px / 4096² limits), draws every legend as vectors and exports a table's
    whole grid.

  • A submenu's entrance played twice when its row was clicked within the
    hover delay, or clicked again while open. Opening cancels the pending hover
    timer, an already-open submenu only closes what is below it and takes
    focus, and a stale timer no longer reopens a submenu after Escape or after
    the pointer left for an ancestor row.

  • A split FluentCalendar replayed the wrong grid's slide. Each panel now
    slides on its own when its page changes, and paging the day grid past
    December moves the month picker to the new year.

  • The scatter chart grew marker 0_0 whenever it had focus; it now grows
    the marker the arrow keys moved to, and nothing on a bare Tab.

  • Charts:

    • an unknown culture (such as 'rs-ss') falls back to the default locale
      instead of throwing during build;
    • a gauge segment hovers on its painted path (not its bounding box),
      strokes its outline on keyboard focus only, and its callout targets the
      segment, the rotated needle or the value text; the title sits on
      upstream's baseline and the value is measured in the font it paints in;
    • the donut popover anchors on its arc, stays open until the pointer leaves
      the chart, and reads in the chart's culture; the polar popover clears its
      marker; the funnel and polar callouts follow their mark on scroll; the
      sankey callout stays where the pointer came in and closes only when the
      pointer leaves the chart;
    • an open HorizontalBarChart popover hides when hideTooltip turns on;
    • the scatter chart builds its callout index once (a 2000-point chart laid
      out in ten seconds before its first hover) and ends its rule where
      upstream does; the area chart's hover listens from the left edge in RTL;
    • an axis-label tooltip near the edge keeps its words whole instead of
      breaking them mid-word;
    • a dashed Vega rule keeps its label border solid; an empty legend adds no
      margin to a barred popover row;
    • the donut and gauge measure only the arc a popover targets (a 30-slice
      hover sweep went from 3.6s to 1.2s in debug);
    • a log y axis draws its default log ticks; mixed number and Date x values
      compare by value, and a Date extent on a numeric axis no longer throws;
    • annotation boxes lay out and paint as the CSS container (max-width,
      border, outer shadows, dashed and dotted borders);
    • legend swatches and popover row markers snap to device pixels, swatches
      rotate about their centre, line swatches in a bar chart are 14x6,
      wrapped legend rows start at the leading edge, and the overflow chevron
      sits in the menu icon slot;
    • VerticalBar and VerticalStackedBar place date bars on upstream's un-niced
      time scale and stand on the height above the label reserve; the
      HorizontalBarChart benchmark triangle sits where upstream draws it;
    • the funnel legend sits right under its height-tall plot and each stage
      paints on its own, so the seam between categories shows; the heat map
      callout body is capped at upstream's 238px, and heat map and gantt
      readings take title2 as non-cartesian callouts;
    • a secondary y axis fills areas to zero; line segments honour
      strokeDashoffset; colour fill bars top out at the data maximum; the
      sparkline stroke is clipped to its plot; a sankey node name collapses its
      white space;
    • a stack callout with two or more line rows no longer throws
      'Duplicate keys found';
    • a numeric yAxisCalloutData reads as a formatted number ('12345' is
      12,345) and an empty one falls back to the y value; a secondary y axis
      no series is on spans 0 to its yMaxValue instead of asserting on NaN;
    • a sankey node name cut short shows whole in the tooltip box beside the
      pointer; a dimmed line series draws no white halo across the highlighted
      one; HorizontalBarChartWithAxis dims its bars on legend hover and prints
      readings as JS does (5000, not 5000.0);
    • hovering a large chart costs less: VerticalBarChart's hover is linear in
      the bar count, stacked bars read their hover targets back instead of
      re-solving them, and a move no longer rebuilds number formats or
      re-measures every tick label.
  • Components: the toast clips only while its height animates; a popover's
    surface is capped only in width, so a tall one no longer squeezes its
    content; the teaching popover dismiss is upstream's bare 12px glyph; a
    labelled list item announces its label once; FluentSearchBox keeps its
    468px cap inside a stretching parent such as FluentField; a hovered
    carousel step mark stays visible in high contrast and snaps its colours as
    CarouselNavButton does; a disabled tag shows not-allowed across the
    whole tag and its resting icon keeps the label colour; FluentSpinButton
    shows no selection handles for a mouse.

Showroom (example app)

  • Storybook's canvas and docs toolbars as upstream renders them — grid,
    backgrounds (PreviewBand), per-element outlines (StoryOutlines), the
    vision simulator filters and width — and toggling any of them keeps the
    story's state; an RTL story sits at the canvas's start edge.
  • Stories wired to the new APIs: chart callouts, legends, locale, event
    annotation colours and label width, the donut popover override, the
    button stories' bundled, menu and checked icons, the tag stories' filled
    glyphs, brand carousel nav, TeachingPopover's first-run carousel, and the
    date picker's error messages from result.message.
  • Chart export now downloads the image; inert knobs were dropped (gradient
    switches, dialog motion, the date range type, the disabled bottom drawer
    buttons) and switch labels no longer change with their value.
  • Fixes to upstream's story details: colourful avatars use upstream's name
    hash, the tree actions are small, empty spin buttons start at 0, the
    title-custom-action dialog has the subtle close, the HBC annotation toggle
    shows the pointer, the card text is readable in dark theme, and copy
    typos are corrected.

fluent_2_core 0.0.4

Fixed

  • FluentApp remounted the whole app the first time it rebuilt after the
    fonts loaded.
    On a platform that loads fonts, build() returned a
    FutureBuilder until they loaded and the app directly on any later rebuild,
    so the root widget type changed and every State below was lost — a parent
    toggling themeMode wiped routes, typed text and scroll positions. It now
    always returns the one FutureBuilder and builds the app as soon as the
    fonts are loaded.
  • Light lavender background2Rest was navy's colour (#73), so lavender
    avatars rendered navy. The palette layer is generated from the Figma file,
    which has that slip and seven more, and no test compared it with React. The
    generator now corrects all eight to Fluent UI React v9 — lavender
    background2Rest (light), red background3Rest and foreground2Rest,
    green foreground3Rest and stroke2Rest, dark red strokeActiveRest (all
    dark), and plum strokeActiveRest (both) — and token_parity_test.dart now
    checks every palette token against React in light, dark and Teams dark.

The font packages stay at 0.0.2; none of them changed.

pub.dev: fluent_2 0.0.6 · fluent_2_core 0.0.4