worksheet 2.3.0
worksheet: ^2.3.0 copied to clipboard
High-performance Flutter spreadsheet widget supporting large datasets, 10%-400% zoom, and GPU-optimized tile-based rendering.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
2.3.0 - 2026-02-12 #
Added #
- Excel-like mouse cursors — crosshair for cells, pointer for headers, resize arrows for column/row borders, move arrow for selection border, crosshair for fill handle
- Auto-fit column/row on double-click resize handle — measures cell content to set optimal width/height; respects
wrapTextstyle for row height calculation - Drag-to-move selection — drag the selection border to relocate cells with a dashed preview border; source cells are cleared after move
- Border double-click jump navigation — double-clicking a selection border edge jumps to the data edge in that direction (Ctrl+Arrow behavior)
Fixed #
- Cell editor stuck at first character on double-click entry
- Double-click auto-fit no longer fires spurious resize-end or selects adjacent column after layout change
2.2.1 - 2026-02-11 #
Fixed #
- Rich text type-to-edit clearing, pending format state, and cell editor alignment
- Wrap-text cell editor expansion lag for right/bottom-aligned cells
- Cell editor edge conditions for bottom overflow and right clipping
- Text selection in cell editor overlay (click-drag, double-click word select)
- Rich text formatting (bold, italic, etc.) lost when committing edit by clicking away from cell
2.2.0 - 2026-02-10 #
Added #
HeaderStyle.darkStyle— dark mode header colors derived from Excel dark modeWorksheetThemeData.darkTheme— dark mode theme preset (dark headers, white cells)HeaderStyle.copyWith(),operator ==,hashCodeSelectionStyle.copyWith(),operator ==,hashCode- Runtime theme switching —
WorksheetThemedata changes now rebuild renderers and layers automatically example/darklight.dart— toggle between light and dark mode with a button
Fixed #
- Header background rects used non-finite dimensions (
double.infinity) which some renderers silently skip — now uses viewport-sized rects _HeaderPainterand_SelectionPaintershouldRepaintdid not detect new layers after theme change
2.1.0 - 2026-02-10 #
Added #
DurationParserclass — parsesH:mm:ssandH:mmstrings intoDurationvalues- Duration parsing in
CellValue.parse()— detection order is now: empty → formula → boolean → number → duration → date → text NumberFormatDetector— auto-detects currency ($1,234.56), percentage (42%), and thousands-separated (1,234) formats on edit commit, returning both parsed value and formatDurationFormatDetector— auto-detects duration formats ([h]:mm:ss,[h]:mm,[m]:ss) on edit commit via round-trip matchingEditController.commitEdit()now detects formats for numbers and durations in addition to dates
2.0.0 - 2026-02-10 #
Added #
- Cell merging —
WorksheetData.mergeCells(CellRange)/unmergeCells(CellCoordinate)withMergedCellRegistryfor merge-aware rendering. Anchor cell keeps its value; non-anchor cells are cleared. Gridlines suppressed across merge interiors. Rendering spans the full merged bounds. - Rich text spans —
Cell.text('...', richText: [TextSpan(...)])for inline bold, italic, underline, color, and strikethrough within a single cell.WorksheetData.getRichText()/setRichText()API. Inline editing with Ctrl+B/I/U/Shift+S formatting shortcuts. - Multi-line cell text —
CellStyle.wrapTextnow fully supported end-to-end: TilePainter, FrozenLayer, and cell editor all respectwrapText. Alt+Enter inserts a newline during editing whenwrapTextis true. Editor grows vertically to fit content. - Auto-detect date format from user input — when a date like
1/15/2024or15-Jan-24is typed, the display format is preserved via round-trip matching against candidateCellFormats DateFormatDetectorutility class for detecting whichCellFormatmatches a user-typed date stringFormatLocale.dayFirstfield — resolves ambiguous numeric dates (e.g.,01/02/2024→ Jan 2 in US, Feb 1 in UK)Worksheet.formatLocaleparameter — passes locale toEditControllerfor date format detection- 7 new date format presets:
dateShortLong(d-mmm-yyyy),dateLong(d mmmm yyyy),dateEu(d/m/yyyy),dateUsDash(m-d-yyyy),dateEuDash(d-m-yyyy),dateUsDot(m.d.yyyy),dateEuDot(d.m.yyyy) CellFormatResultclass — rich formatting result with optional color override from format codes like[Red]or[Color3]CellFormat.formatRich()method — returnsCellFormatResultwith text and optional color (vsformat()which returns plain text)FormatLocaleclass with 6 built-in locales (enUs,enGb,deDe,frFr,jaJp,zhCn) — locale-aware decimal/thousands separators, currency symbols, and month/day names- Comprehensive Excel custom format engine: conditional sections (
[>100]), color codes ([Red],[Color3]), bracket metadata ([$EUR]currency override), comma-as-scaler,*repeat fill, fractional seconds, fraction denominator constraints
Fixed #
- Zero-padded date formats (e.g.,
01/02/2024) andyyyy-mmm-ddpatterns now detected correctly byDateFormatDetector
Changed #
onCommitcallback signature now includes optional{CellFormat? detectedFormat}parameter acrossEditController,CellEditorOverlay, andWorksheetWorksheetcommit handlers auto-apply detected date format viadata.setFormat()when no explicit format exists- FrozenLayer now respects
CellStyle.wrapText(previously hardcodedmaxLines: 1)
1.10.0 - 2026-02-09 #
Changed #
- Rewrote date/time formatter with token-based pipeline for correct context-sensitive
m/mmdisambiguation - Reworked
CellEditorOverlayto useTransform.scaleat base font size (matching tile painter's GPU scaling) with glyph-based cursor height - Editor overlay now clips behind headers using a positioned Stack
Added #
mmmmmformat token — first letter of month nameA/Panda/pformat tokens — abbreviated AM/PM markerssformat token — unpadded secondsmmmmanddddd/dddformat tokens now handled via tokenizer (previously worked but fragile)- Bundled full Roboto font family (Regular, Bold, Italic, BoldItalic) for bold/italic cell styling
CellStyle.defaultFontFamilyconstant andWorksheetThemeData.resolveFontPackage()for correct package font resolutionCellStyle.implicitAlignment()— Excel-like value-type alignment (numbers/dates right, text left) when no explicit alignment is set
1.9.0 - 2026-02-08 #
Added #
- Selective cell clearing via
ClearCellsIntentflags (clearValue,clearStyle,clearFormat) — clear values, styles, or formats independently while preserving the rest Ctrl+\/Cmd+\keyboard shortcut for "Clear Formatting" (removes styles and formats, keeps values)
1.8.0 - 2026-02-08 #
Added #
CellValueType.durationandCellValue.duration()for storing elapsed time / duration valuesCell.duration()constructor andWorksheetDurationextension (.cellonDuration)CellFormatType.durationwith Excel-style bracket notation format codes ([h]:mm:ss,[h]:mm,[m]:ss,[s])- 3 duration format presets:
CellFormat.duration,CellFormat.durationShort,CellFormat.durationMinSec - Duration formatting engine supporting bracketed accumulating units and negative durations
1.7.0 - 2026-02-08 #
Added #
- Cell border styling with line styles (
solid,dotted,dashed,double) andBorderResolverfor adjacent-cell conflict resolution matching Excel/Sheets rules BorderPainterutility for rendering all border line styles in tiles and frozen layerskeepAnchorVisibleonWorksheetController— automatically adjusts scroll when zoom changes so the selected cell stays visible and fully in viewcopyWithmethods onBorderStyleandCellBorders
1.6.3 - 2026-02-08 #
Fixed #
- Virtual keyboard now appears immediately on double-tap editing on iOS Safari — moved cell editor overlay outside gesture interceptors and added synchronous focus trigger to satisfy Safari's user-gesture requirement
- Cell editor overlay uses dedicated FocusScope to ensure autofocus fires independently of the worksheet's existing focus tree
1.6.2 - 2026-02-06 #
Added #
- Worksheet automatically scrolls to center the editing cell vertically when virtual keyboard appears, keeping it visible above browser URL bars and other UI elements
1.6.1 - 2026-02-06 #
Fixed #
- Keyboard navigation now works immediately after editing completes on all platforms (web, macOS, mobile)
- Focus restoration uses explicit
FocusNodeand post-frame callback to avoid timing conflicts with tap events - Software keyboard reliably activates on mobile when cell editing starts
1.6.0 - 2026-02-06 #
Added #
CellEditorOverlaynow respects per-cell styles (font size, family, weight, style, color, text alignment) to match the tile-rendered cell appearanceautofocus: trueon cell editor TextField to ensure software keyboard activates on mobile
Fixed #
- Gridlines and selection borders snap to half-pixel positions (+0.5) for crisp 1px rendering on Impeller — prevents gray anti-aliased lines
- Removed devicePixelRatio strokeWidth adjustment that caused sub-pixel blending artifacts
- Cell editor overlay text now aligns precisely with cell content using measured TextPainter height
- Cursor height matches font size instead of default line height
- Double-tap to edit places cursor at end instead of selecting all text (F2 still selects all)
- Focus returns to worksheet after editing instead of previous widget (e.g., zoom slider)
Changed #
- Default gridline color changed to
0xFFD4D4D4
1.5.0 - 2026-02-03 #
Added #
CellValue.parse()— unified static factory that detects type from text input (formula, boolean, number, date, text) with consistent behavior across editing and clipboard pasteWorksheet.dateParserparameter — configures date format detection viaAnyDatefrom theany_datepackage; supports locale-based parsing (e.g.,AnyDate.fromLocale('en-US')for month/day/year)- Date detection during editing and clipboard paste — typing
2025-01-15orJan 15, 2025now commits asCellValue.date()instead of text - Re-exported
AnyDateandDateParserInfofromworksheet.dartso consumers don't need a directany_datedependency
Changed #
EditController._parseTextnow delegates toCellValue.parse()for consistent type detectionTsvClipboardSerializer._parseValuenow delegates toCellValue.parse(allowFormulas: false)— clipboard paste no longer interprets=prefix as a formula, trims whitespace, and uses case-insensitive boolean detectionTsvClipboardSerializerconstructor accepts optionaldateParserparameterWorksheet.clipboardSerializeris now nullable (defaults toTsvClipboardSerializerwith the widget'sdateParser)
Fixed #
- Clipboard paste boolean detection was case-sensitive (
trueworked butTRUEdid not) — now case-insensitive - Clipboard paste did not trim whitespace — now trims consistently
- Clipboard paste used
num.tryParsewhile editing useddouble.tryParse— both now usedouble.tryParse
1.4.0 - 2025-02-02 #
Added #
- Flutter
Shortcuts/Actionspattern for keyboard handling — enables consumers to override, extend, or remap any keyboard shortcut Worksheet.shortcutsparameter — custom shortcut bindings merged on top of defaultsWorksheet.actionsparameter — custom action overrides merged on top of defaultsDefaultWorksheetShortcuts— static map of ~44 default shortcut bindings (bothcontrol:andmeta:variants for cross-platform)- 13 Intent classes (
MoveSelectionIntent,GoToCellIntent,ClearCellsIntent, etc.) - 13 Action classes with
WorksheetActionContextinterface for dependency injection WorksheetActionContext— abstract interface implemented by the widget state, avoiding 6+ constructor params per Action- New shortcuts: Ctrl+C/X/V (copy/cut/paste), Ctrl+D (fill down), Ctrl+R (fill right), Delete/Backspace (clear cells)
Worksheet.editControllerparameter for integrated cell editing — rendersCellEditorOverlayinternally, handles type-to-edit, commit-and-navigate, and F2/double-tap editing- Type-to-edit: printable characters start editing the focused cell with that character as initial content
- Commit-and-navigate: Enter (down), Shift+Enter (up), Tab (right), Shift+Tab (left) commit the edit and move selection
CellEditorOverlay.onCommitAndNavigatecallback for directional commit with row/column delta- Arrow keys commit the edit and navigate when editing (via
CellEditorOverlay) - Tap outside the editing cell commits the current edit
EditCommitResultvalue class onEditController- Backspace/Delete tests for editing vs navigation mode
Deprecated #
KeyboardHandlerclass — use theShortcuts/Actionspattern instead (seeworksheet_intents.dart)
Changed #
Worksheetwidget now usesShortcuts->Actions->Focuswidget tree instead ofFocus(onKeyEvent:)withKeyboardHandler- Destructive actions (
ClearCells,Cut,Paste,FillDown,FillRight) checkreadOnlyinisEnabled()as defense-in-depth - Cell-level actions (copy, cut, paste, clear, select-all) are disabled while the
editControlleris editing, so Ctrl+C/X/V/A and Backspace/Delete reach the text field for in-cell editing CellEditorOverlayusesTextFieldwithInputDecoration.collapsedfor proper cursor rendering, text selection, and double-click word selection- Parent double-tap handler suppressed while editing so the TextField's word-select gesture wins the gesture arena
- Pointer-down within the editing cell is passed through to the TextField for cursor repositioning instead of committing the edit
TilePainter.editingCellfield hides tile-rendered text for the cell being edited (avoids double rendering)
1.3.0 - 2025-02-02 #
Added #
WorksheetController.getCellScreenBounds()— returns screen-spaceRectfor a cell, accounting for zoom, scroll offset, and headersWorksheetController.ensureCellVisible()— simplified scroll-to-cell that uses the attached layoutWorksheetController.hasLayout/layoutSolver/headerWidth/headerHeight— public read access to the widget's internal layout stateWorksheetController.attachLayout()/detachLayout()— called by theWorksheetwidget to share its internalLayoutSolver
Fixed #
- Cell text disappearing on alternating rows after column resize — cell backgrounds straddling a tile boundary overflowed into adjacent tiles because
PictureRecordercullRectis only a hint; added hardclipRectto tile canvas - Deferred
TextPainterdisposal until afterPictureRecorder.endRecording()to prevent premature nativeParagraphresource release
Changed #
Worksheetwidget now attaches itsLayoutSolverand header dimensions to the controller after initialization- Simplified
_ensureSelectionVisibleinWorksheetto useensureCellVisible - Example app no longer creates a duplicate
LayoutSolver; usescontroller.getCellScreenBounds()instead - Updated GETTING_STARTED.md, COOKBOOK.md, API.md, and ARCHITECTURE.md to reflect the new API
1.2.0 - 2025-01-30 #
Added #
CellFormatclass with Excel-style format codes for cell display formatting- 16 built-in format presets (currency, percentage, date, scientific, fraction, etc.)
CellFormatTypeenum with 12 format categoriesCell.formatfield for per-cell formattingCell.displayValuegetter — uses format when presentCell.copyWithFormat()methodWorksheetData.getFormat()/setFormat()with backward-compatible defaultsSparseWorksheetDataformat storage with change events and batch supportDataChangeType.cellFormatevent type
Changed #
TilePainterandFrozenLayeruseCellFormatwhen rendering cell contentCell.isEmptyconsiders format field
Deprecated #
CellStyle.numberFormat— useCellFormatonCellinstead
1.1.0 - 2025-01-27 #
Added #
- Built-in keyboard navigation in Worksheet widget (arrow keys, Tab, Enter, Home/End, PageUp/Down, F2, Escape, Ctrl+A)
- 18 widget-level keyboard navigation tests
- Release process checklist in CLAUDE.md
Fixed #
- Selection and header layers now repaint on selection change (CustomPainter repaint listenable)
Changed #
- Simplified example/main.dart by removing manual keyboard handling code
- Updated COOKBOOK.md keyboard navigation section to reflect built-in support
1.0.1 - 2025-01-25 #
Added #
- Screenshot in README.md via golden test
- GitHub Actions CI workflow for automated testing
- Codecov integration for coverage reporting
- Roboto font bundled for consistent text rendering
Fixed #
- Resolved all dart analyzer warnings in lib/ and test/
- Fixed installation instructions to use pub.dev version
- Golden tests excluded from CI (platform-dependent font rendering)
Changed #
- README badges: pub.dev version, license, CI status, coverage
1.0.0 - 2025-01-25 #
Added #
- Example application with 50,000 rows of sample sales data
- Performance benchmarks for tile rendering (< 8ms target)
- Performance benchmarks for hit testing (< 100μs target)
- Scroll performance benchmarks
- Large dataset integration tests
- Memory leak tests
- Comprehensive documentation suite:
- ARCHITECTURE.md with rendering pipeline deep dive
- GETTING_STARTED.md with installation and basic usage
- COOKBOOK.md with practical recipes
- PERFORMANCE.md optimization guide
- THEMING.md customization guide
- TESTING.md testing patterns
- API.md quick reference
- Updated PLAN.md to reflect completed implementation
Changed #
- Version bumped to 1.0.0 for production release
0.9.0 - 2024-01-24 #
Added #
WorksheetWidget- Main public StatefulWidgetWorksheetController- Programmatic control aggregating sub-controllersWorksheetThemeData- Complete theming and styling supportWorksheetTheme- InheritedWidget for theme propagation- Complete public API exports in
worksheet.dart - Gesture handling integration
- Layer composition using Stack
0.8.0 - 2024-01-23 #
Added #
RenderLayer- Abstract interface for render layersSelectionLayer- Selection highlight paintingSelectionRenderer- Selection visual renderingHeaderLayer- Row and column header layerHeaderRenderer- A,B,C column and 1,2,3 row labelsFrozenLayer- Infrastructure for frozen panes (not fully wired)
0.7.0 - 2024-01-22 #
Added #
EditController- Cell editing orchestration with start/commit/cancel flowEditTriggerenum - Double-tap, keyboard, and typing triggersCellEditorOverlay- Floating text editor widget for cell editing
0.6.0 - 2024-01-21 #
Added #
SelectionController- Selection state machine with single/range/row/column modesHitTester- Coordinate resolution from screen to worksheet spaceHitTestResult- Types for cell, header, and resize handle hitsGestureHandler- Unified gesture processingKeyboardHandler- Arrow keys and keyboard shortcutsScaleHandler- Pinch-to-zoom gesture handling
0.5.0 - 2024-01-20 #
Added #
ZoomController- Zoom level management extending ValueNotifier- Support for 10%-400% zoom range (0.1 to 4.0)
zoomIn(),zoomOut(), andreset()methods- Zoom clamping and validation
0.4.0 - 2024-01-19 #
Added #
ScrollAnchor- Position preservation during zoomWorksheetScrollPhysics- Custom scroll momentum physicsViewportDelegate- Interface for viewport managementWorksheetViewport- TwoDimensionalScrollable integrationWorksheetScrollDelegate- Child management for 2D scrolling
0.3.0 - 2024-01-18 #
Added #
TileCoordinate- Tile grid position representationTileConfig- Configuration with 256px tiles, LRU cache settingsTile- Single cached tile with GPU-backedui.PictureTilePainter- Cell painting with level-of-detail (LOD) renderingTileCache- LRU eviction cache for tilesTileManager- Tile lifecycle orchestration
Performance #
- GPU-backed tile caching for smooth scrolling
- Level-of-detail rendering based on zoom level
- LRU cache eviction to manage memory
0.2.0 - 2024-01-17 #
Added #
WorksheetData- Abstract interface for worksheet data accessSparseWorksheetData- Map-based sparse storage implementationDataChangeEvent- Granular change events for reactive updatesSpanList- Cumulative row/column sizes with O(log n) lookupsLayoutSolver- Position to index conversionVisibleRangeCalculator- Viewport to CellRange queriesZoomTransformer- Zoom-aware coordinate math with ZoomBucket enum
Performance #
- O(log n) binary search for position lookups
- Memory-efficient sparse data storage
0.1.0 - 2024-01-16 #
Added #
- Initial project scaffolding
CellCoordinate- Immutable (row, col) address with Excel notation (A1, AA100)CellRange- Rectangular cell selection with normalization and contains()CellValue- Union type supporting text, number, boolean, formula, error, dateCellStyle- Font, color, alignment, and border stylingFreezeConfig- Configuration for frozen panes- Full test coverage for all core models
- CLAUDE.md development guide
- PLAN.md implementation plan
Technical #
- TDD workflow with tests written before implementation
- SOLID principles applied throughout
- Immutable models with proper equality/hashCode
