adaptive_stat_card 0.2.0
adaptive_stat_card: ^0.2.0 copied to clipboard
An overflow-safe Flutter stat card widget for dashboards, with adaptive text fitting, accessibility text-scale support and zero runtime dependencies.
0.2.0 - 2026-08-30 #
Added:
StatCardSyncScope: an inherited scope that makes everyStatCardbeneath it converge on a single font size — the smallest any card in the group needed — so a row of cards reads as one object instead of five independently fitted ones. Values synchronise with values and labels with labels. Cards report the size they would have picked on their own rather than the size they were told to paint, so the minimum is a fixed point after one extra frame and cannot oscillate; adding and removing cards recomputes it both ways. Without a scope every card behaves exactly as it did in 0.1.0.StatCard.number(num value, {StatCardValueFormat format = .auto, ...}): degrades the value semantically before it shrinks the font. The ladder is1,250,000→1.25M→1.2M, and only then the existingStatCardOverflowchain. The accessibility label always reads the full grouped number, whatever is painted.StatCardNumberFormat, a dependency-freegrouped/compactformatter, andStatCardValueFormatto pick betweenauto,groupedandcompact. The output is en-style and deliberately not localised; supplyvalueFormatter: (num value, double availableWidth) => ...to plug inintlor anything else. Compact digits are truncated rather than rounded, so1.25Mshortens to1.2Minstead of jumping to1.3M.sparkline: List<double>?: a trend line drawn under the label by aCustomPainter, with no charting dependency. It is omitted entirely when the series has fewer than two points or the card is narrower thanStatCard.sparklineMinWidth(96 px of content). Colour and thickness come from the newStatCardThemeData.sparklineColorandStatCardThemeData.sparklineStrokeWidth.animateValue: boolonStatCard.number: counts from the old reading to the new one with aTweenAnimationBuilder, suppressed whenMediaQuery.disableAnimationsis set. Only the two endpoints are measured, so a count in flight adds nothing to the shared measurement cache.error: Object?, which renders an error glyph in place of the value, keeps the label, and exposes the message as a tooltip and to screen readers; it takes precedence overisLoading.emptyPlaceholder: String = '—', rendered when the value is empty, so a metric with no reading is visibly different from one still loading.onLongPress: VoidCallback?andselected: bool, both reflected in the card's semantics; a selected card takes the theme's icon colour as its border and doubles its border width.clearFitCache(),debugFitCacheLength()andkFitCacheMaxEntries, for tests that need a cold measurement cache or want to assert it stays bounded.
Fixed:
- The text-fit cache is now a real 200-entry LRU. It was keyed on the value string and guarded only by a clear-everything-at-512 check, so a dashboard refreshing its numbers filled it up and then discarded every warm entry at once. Eviction is now least-recently-used, one entry at a time.
StatCardGridcountsspacingwhen choosing its column count. It divided the available width byminCardWidthalone and so claimed a column the row could not pay for: a 600 px grid of 100 px cards was split into six 90 px columns. The count is now((maxWidth + spacing) / (minCardWidth + spacing)).floor(), clamped as before, and no card is ever narrower thanminCardWidth. Grids near a breakpoint may drop one column relative to 0.1.0 — that is the fix.
Notes:
StatCardOverflow.tooltipandonTapwere verified not to conflict on touch devices: a long press opens the tooltip without firingonTap, and a tap firesonTapwithout opening the tooltip. Both directions are now covered by tests.- A non-loading card with an empty
valuenow rendersemptyPlaceholderinstead of nothing. - The stress suite gained 88 cases over the new surface at text scales 1.0, 1.3, 1.75 and 2.0 across widths of 80 to 240 px.
0.1.0 #
- Initial release.
Features:
StatCard: an overflow-safe dashboard stat card with a value, label, optional icon, unit suffix and trend badge, plusStatCard.compactandStatCard.loadingpresets.- Seven overflow strategies:
wrap,ellipsis,tooltip,shrink,shrinkThenWrap(default),shrinkThenTooltipandscroll. - Binary-search text fitting that measures with the ambient
MediaQuery.textScalerOf(context), so accessibility text scaling shrinks or wraps instead of overflowing. Results are cached per text, constraint, scaler and style. - Tooltips are attached only when the text was actually truncated.
- Four layouts:
iconLeading,iconTrailing,iconAboveandnoIcon. - Three-level theming through
StatCardThemeDataas aThemeExtension, aStatCardThemeinherited scope, and a per-widget override, merged field by field over a fallback derived fromColorSchemeandTextTheme. StatCardGrid: a responsive grid driven byminCardWidth, safe from 240 px to 2000 px.StatTrendwith up, down and flat directions and per-instance colour overrides.- Loading skeletons animated with a plain
AnimationControllerthat respectMediaQuery.disableAnimations. - Single-node semantics per card, RTL-aware padding and alignment.
- Zero runtime dependencies; supports Android, iOS, web, macOS, Windows and Linux.
