fitgrid_table 0.1.4
fitgrid_table: ^0.1.4 copied to clipboard
A fast Flutter data table and data grid that measures column widths and paints cells: sorting, filters, cell editing, grouping and xlsx export over a million rows.
Changelog #
0.1.4 #
Filtering and text #
- A filter row.
FitGrid.showFilterRowputs a field under each header whose column has afilterspec. You filter as you type:abccontains,=abcequals, and on number and date columns>5,<=2024-06-30or10..20. A checklist column gets a button that opens its dialog. The row edits the samecontroller.filteras the column menu, so each shows what the other set. A filter the short form can't express shows as the field's hint. FitGridColumnFilter.parseandtoText. The filter row's parser and formatter, public so a filter box of your own can use them.- Translatable text.
FitGridStringsholds every string the grid shows or announces: menus, pager, filter dialog and row, empty state and screen reader labels. Extend it and override what you need. Supply it withFitGrid.strings, withFitGridLocalizationsfor a subtree, or withFitGridStringsDelegateby locale.showFitGridFilterDialogandshowFitGridColumnDialogtakestrings:.
Fixes #
- The pager fits a phone. Below 520 pixels it drops the "Rows" caption. Below 420 it also drops the page-size picker and the first and last page buttons. Before, it overflowed at phone width.
- A grid shorter than its header and pager clips instead of overflowing.
An
Expandedgrid can get very short when a phone keyboard comes up. The grid now keeps one row and clips the bottom rather than throwing a layout error. - Selection, focus and an open editor stay on their record. Before, they
were positions: a sort, a filter or a rows update left them on whatever
record slid into that slot, and text typed into an open editor could be
committed to a different record. Now the controller re-points them to where
their records went, matched by
rowKeyor by the row object. A record that is filtered out leaves the selection, and the focus or the editor on it closes. What you have typed survives the reorder and commits to the record you typed it into.onSelectionChangedreports the new indices.
Compatibility #
FitGridColumnChooser.tooltipandshowAllLabelare now nullable, and so are the label parameters offitGridColumnChooserItemsandshowFitGridColumnDialog. Null means the translated default. Code that passes them works unchanged. Code that reads the two fields as aStringneeds a!or a fallback.
Everything else is opt-in: a grid that sets neither showFilterRow nor
strings looks and behaves as before, except for the two fixes.
0.1.3 #
Gestures and columns #
- Double-tap and long-press callbacks.
FitGrid.onRowDoubleTap,onCellDoubleTap,onRowLongPressandonCellLongPress, with global row indices likeonRowTap. A double-tap still opens the editor under the defaulteditTrigger. A long-press callback takes the long-press from the context menu, which stays on right-click. Group headers and the checkbox, detail and drag columns report neither. FitGrid.onColumnResized. Fires once when a resize drag ends, with the width, and withnullwhen a double-click or the column menu hands a column back to its width policy.- Size all columns to fit. A column menu entry that hands every resized
column back to its policy, as
controller.columns.autoSizeAll()does.
All three are opt-in: a grid that sets none of them behaves as before.
Fixes #
- A resized column now follows the pointer when
stretchColumnsToFillis on, which is the default. The dragged width used to be stretched again to fill the grid, so the divider jumped away on the first move and then ran ahead of the finger. A resized column now keeps the width it was dragged to, and the columns nobody has resized share the leftover space. - Dragging a divider back after pushing a column past its
max(or below itsmin) takes effect at once. Before, the overshoot was banked and the column stayed put until the pointer had moved all of it back.
Docs #
- The changelog now has entries for every published version, 0.1.2 included, so pub.dev can match it to the release.
0.1.2 #
No code changes from 0.1.1.
Docs #
- Adds the 0.1.1 notes to the changelog, which were missing from the 0.1.1 upload.
0.1.1 #
Theme #
- Dashed row rules.
FitGridThemeData.rowDividerDashtakes alternating dash and gap lengths, such as[3, 2]. The pattern starts at the grid's left edge, so pinned and scrolling columns line up. - Short column dividers.
FitGridThemeData.columnDividerExtentdraws body column rules as short ticks centred in each row, incolumnDivider's colour.headerDividerExtentdoes the same for the dividers between header cells. Both default to null, which keeps the full-height lines.
Fixes #
- Columns now size to fit their footer totals, so a sum wider than every cell above it is no longer cut off.
- A footer label and its value are laid out as one line. A long total is no longer cut off while there is still room beside a short label.
Docs #
- The README is now a full guide and API reference, with a live demo, a website, and screenshots on pub.dev.
0.1.0 #
The release that turns a fast table into a grid people can work in. Every feature below is opt-in or invisible until used: an existing grid looks and behaves as it did, and the package still has no dependency beyond Flutter.
Sorting, columns and filters #
- Multi-column sort. Shift+click adds a column to the sort; sorted headers
show their priority.
FitGridController.setSort/clearSort,toggleSort(additive:),FitGridSortKey, and a stable multi-key sort. Data sources getsortByKeysandFitGridPageRequest.sortKeys, defaulting to the primary key so existing sources keep working.FitGrid.multiSortturns the gesture off. - Column menu.
FitGrid.showColumnMenuputs a menu on every header: sort, filter, pin to either edge, size to fit, hide, and the column chooser.columnMenuBuilderedits it. - Column chooser.
FitGridColumnChooser,showFitGridColumnDialogandfitGridColumnChooserItems.FitGridColumn.hideable; the column state gainsshowAllandsetFreeze. - Filter UI.
FitGridColumn.filterwithFitGridFilterSpec.text,.number,.dateor.values(a searchable checklist). Filters are data —FitGridColumnFilter, JSON round-trippable — held inFitGridFilterState.filters, shown as a header glyph, and forwarded to data sources throughfilterByandFitGridPageRequest.filters. - Header bands.
FitGrid.columnGroupswithFitGridColumnGroup. - Saved layouts.
controller.saveState()/restoreState()withFitGridSavedState: order, visibility, pins, widths, sort, filters, search and page.
Cells #
- Range selection.
FitGrid.cellSelection: mouse drag with edge auto-scroll, Shift+click, Shift+arrows. Ranges copy as blocks, and live onFitGridController.range. - Paste and clear. Ctrl+V pastes a block, or fills a range with one value;
Delete/Backspace clears. Every value goes through the column's validator and
commit.
fitGridParseDelimited,FitGridCellEdit. - Fill handle. Drag the range's corner to continue series or repeat values
—
fitGridFillSeries. - Undo and redo. Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y over typed edits, pastes,
clears and fills;
controller.undo()/redo()andFitGridController.history.FitGrid.enableUndo. - Charts in cells.
FitGridColumn.visualwithFitGridCellVisual.bar,.progressand.sparkline, painted by the text pass.
Rows #
- Detail rows.
FitGrid.detailBuilderopens a full-width panel under a row from a chevron column; panels follow their row byFitGrid.rowKeyand compose with grouping, trees and pagination.FitGridController.details. - Sticky group headers, stacked and pushed away by the next group. On by
default (
FitGrid.stickyGroupHeaders); a grid at rest is unchanged. - Row reordering.
FitGrid.reorderableRowswith drag handles and Alt+Up/Down;onRowReorderfor hosts that own their list. - Infinite scroll.
FitGrid.onLoadMore,hasMoreRows,loadMoreThreshold,loadingRowCount, with skeleton rows while loading. Rows a data source has not delivered now paint as skeletons too.
Export and analysis #
- xlsx export.
fitGridToXlsxwrites a workbook in pure Dart — no new dependency, and it runs on the web. - Pivots.
fitGridPivotwithFitGridPivotDimension,FitGridPivotValueandFitGridAggregationproduces an ordinary grid's rows and columns, with grand totals reduced from the source rows.
Theming #
FitGridThemeData.rowDividerDashdraws row rules dashed;columnDividerExtentandheaderDividerExtentdraw column dividers as short centred ticks in the body and the header. All off by default.
Fixes #
- Keys typed into an open editor no longer reach the grid: Space used to toggle the row's selection and the arrow keys moved the grid's focus. Grid shortcuts now act only while the grid itself holds focus.
- Each cell's spec is resolved once per paint rather than twice.
- Footer totals are no longer cut off: columns size to fit their footer total as well as their header and cells, and the footer lays its label and value out as one line instead of giving each half the room.
Other #
- The minimum Flutter version is now stated correctly as 3.35 (Dart 3.9), which the package already required.
- Agents working with the package can install its skill with
dart run skills@ get— seeskills/. - A website with a live demo of the example gallery: https://fitgrid-e734.vercel.app/demo/
- Screenshots on the pub.dev page, a sharper package description, and topics that match how people search for a data table.
- The example gallery gains six pages: spreadsheet editing; columns, filters and saved layouts; pivot and export; detail rows with nested grids; infinite scroll against a slow, failing feed; reorderable rows; and charts in cells.
0.1.0-dev #
The release that closes the gaps between "interesting approach" and "you could ship this".
Accessibility #
- Painted cells now reach the accessibility tree. The render object
assembles its own: a
tablenode holding onerowper visible row and onecellper visible cell, recycled across updates and bounded by the window, so a screen reader sees a real table while the cost still tracks the viewport. This was the structural objection to painting rather than building, and it is answered in the render layer rather than left to the caller. FitGridColumn.semanticValuesays something different from the painted text when the painted text is written for the eye.- Headers announce as headers, and a selected row announces as selected.
Frozen columns #
FitGridColumn.freezedoes what it always claimed to. Pinned columns are pulled to the edges whatever order they were declared in, and the header, the body and the footer share one band geometry rather than three that drift.- All horizontal placement now goes through a single leading-edge function, which makes RTL one mirror instead of a special case in painting, hit testing, semantics and overlay placement.
Selection and keyboard #
FitGridSelectionMode, a selection anchor, and the replace / toggle / extend gestures every desktop table has.FitGrid.showSelectionColumnadds a pinned checkbox column — painted as a glyph, so a selectable grid does not put a widget back into every row — with a tri-state select-all box in the header.- A focus model with a focused cell: arrows, Home/End, Ctrl+Home/End, Page Up/Down, Space, Enter, Ctrl+A, Escape, and Ctrl+C copying as TSV. Tab is deliberately unbound: a widget a keyboard user cannot leave is worse than one they cannot enter.
FitGridController.scrollTobrings a row, and optionally a column, into view — turning the page first when paginated, and never behind a pinned column.
Data #
- Filtering and search in their own notifier, so a keystroke re-derives the row view without re-measuring a column. Matches are highlighted from the painter that has already been laid out, which costs a rectangle rather than a rebuilt span tree.
- Data sources:
FitGridDataSourceandFitGridAsyncDataSourcefor rows the grid does not hold, fetched a page at a time behind a bounded cache. Sorting and filtering are forwarded rather than applied to a window. - Grouping and tree rows, which flatten to the same list of display lines, so neither gets its own path through the renderer, the hit tests or the semantics. Collapsing never renumbers the rows below it.
- Merged cells underneath both: a span resolver lets one cell cover several columns, across a pinned boundary if it has to.
- Aggregate footer via
FitGridColumn.aggregate, computed over the rows on screen — filter included, because a total the user cannot add up themselves is a total they are right not to trust. - Export:
FitGridExportData,fitGridToCsv,fitGridToTsv. Rows, not files — see the type's docs for why the format writers are not in here. - Column reordering by dragging a header, opt-in through
FitGrid.reorderableColumns. - Context menus, a painted row hover, and
FitGrid.rowColorfor conditional formatting that costs adrawRectper row rather than aContainer. - Widget cells.
FitGridColumn.cellBuildernow renders: real widgets in cells, built during layout for the rows on screen and dropped as they scroll away, as a sliver list does. They are clipped to their band beneath pinned columns and hit-tested within it. A widget that handles its own taps keeps them rather than also selecting the row. Overlay children, the editor included, are now clipped to their band as well. - A data source that starts with no known rows now loads. With the default
initialRowCount: 0the grid had nothing to lay out, so nothing reported a window and the first page was never requested. A search, which resets the count, stranded the grid the same way. FitGridAsyncDataSource.disposedrops fetches still in flight, instead of notifying from a disposed source when the answer lands after the screen that owned it has gone.
Performance #
- Painters are keyed by what they contain rather than by where they are, so a column of four hundred rows reading "Active" lays that word out once, and a scroll reuses what it is scrolling over.
FitGridOverflow.fadeno longer opens asaveLayerper truncated cell per frame. The ramp is painted into the glyphs through a gradient foreground.measureAllRowsis rationed to a budget per pass and resumed on the next build, so a large table gets a first frame. Widths only grow towards the truth.- Cached
visiblecolumns, so a scroll frame stops rebuilding the list.
Packaging #
- Published on pub.dev as
fitgrid_table. Importpackage:fitgrid_table/fitgrid_table.dart, andpackage:fitgrid_table/testing.dartfor the test helpers. flutter_testis no longer a runtime dependency. It was one becausetesting.darttook aWidgetTester; the helpers now find the grid themselves. They no longer take atesterargument, andexpectFitGridCell/expectFitGridRoware gone — use your ownexpectonfitGridCellTextandfitGridRowText.- Published benchmarks in
benchmark/, and golden tests covering light, dark, densities, all four overflow policies, RTL, frozen columns, grouping and search highlighting.
Example #
- The example app is now a gallery: two unrelated designs over the same data, pagination three ways, conditional formatting, sizing with live frame timings, lazy loading against a fake server, controller patterns with a rebuild counter, grouping and tree rows, and the full playground. Each page explains what to copy and what to avoid.
Breaking #
FitGrid.selectionModeis nullable and defaults to null, meaning "leave the controller alone". Previously a default was pushed onto a caller-supplied controller and silently cleared any selection set before the first build.FitGridCellStyle, and the newFitGridCellIcon/FitGridCellIconColor, receive the row's index into the full row list rather than into the page.package:fitgrid_table/testing.darthelpers no longer take aWidgetTester.FitGridRowSizer.resolvetakes aFitGridRowsViewrather than aList.
0.0.1-dev #
Foundation release. Not published.
FitGridwith content-measured column widths (auto,fixed,flex,fitHeader, each with min/max clamps)- Content-measured row heights (
FitGridRowHeight.contentSized) paired withFitGridColumn.maxLinesfor wrapping cells; row geometry lives inFitGridRowMetrics, arithmetic when rows share a height and a prefix-sum binary search when they do not - Interactive column resizing: a grip on every resizable divider, drag it to
set a width,
double-click it to re-fit. Clamped by the column's own policy, mirrored for
RTL, and available programmatically as
FitGridColumnState.setWidth/autoSize/autoSizeAll - Cell text is capped to the lines its row can afford, and clipped to its own box if it still does not fit, so a wrapped or clamped cell can no longer paint over its neighbours
- All four
FitGridOverflowpolicies implemented:fadecuts an alpha ramp out of the glyphs so it reveals the real background, andtooltipOnTruncateshows a label on exactly the cells that lost text, using truncation the renderer had already recorded - Pagination with no dependency and no copying:
FitGridPageViewis a read-only window onto the row list, widths are still measured against the whole dataset so columns do not jump between pages, and row indices stay global so selection survives paging. Built-inFitGridPager, or replace it withpagerBuilder - Inline editing via
FitGridColumn.editor: one editor widget exists, and only while a cell is open, as an overlay child of the painted section. Validation, Enter/Escape/Tab, commit-or-discard on focus loss, custom editor builders, and row indices that stay global under sorting and pagination - Painted text cells via
RenderFitGridSection, with prunedTextPaintercaching and batched rule drawing - Row windowing driven by the viewport, so layout cost tracks the screen rather than the dataset
FitGridController— data, column and selection state as separateChangeNotifiersFitGridThemeData, derivable fromThemeData, with three densities- Right-to-left support in measurement, layout and paint
package:fitgrid_table/testing.dartfor asserting on painted cells
