Skip to content

Releases: stephenWanjala/DataTable

0.4.0

Choose a tag to compare

@stephenWanjala stephenWanjala released this 28 Aug 17:05
e24d07b

A fix release. No signatures changed, so 0.4.0 is a drop-in for 0.3.0 — but four things the
documentation promised and the code did not actually do now work, so the table may behave in ways
your 0.3.0 workarounds were compensating for. Those two cases are called out below.

implementation("io.github.stephenwanjala:datatable:0.4.0")

Sorting cycles past ascending

Clicking a header in 0.3.0 always sorted ascending, however many times you clicked it. The
click handler captured the sort state from its first composition and never saw an update, so the
cycle logic always compared against an empty SortState.

Clicking now cycles ascending → descending → none. Multi-sort with Ctrl+click was stuck
the same way and is fixed with it.

⚠️ If you worked around this by inverting the order yourself in onSortChange, remove that — you
will now get the inversion twice.

Keyboard navigation works at all

The table never took focus, so no key event ever reached it and every shortcut was dead in every
release to date. It now requests focus when clicked, and arrow keys, Home,
End, Enter, and Space behave as documented.

Focus is taken on click rather than on appearing, so a table dropped into a form still does not
steal focus from whatever the user is typing in.

Tabbing past a table no longer costs a stop per row

Per-row checkboxes and expand buttons are out of the Tab order. Previously a three-row table with
selection and expansion took eight Tab presses to get past, and a forty-row grid took
eighty. The cost is now fixed regardless of row count.

Both controls stay clickable, and Space on the focused row still toggles selection. The
header select-all checkbox and the pagination controls keep their focus — there is a fixed handful
of them, and they are real controls a keyboard user should reach.

Weighted columns have a real width

A column with width = null collapsed to zero inside the horizontally scrolling area, because
Modifier.weight had nothing bounded to take a share of. Weighted columns now divide up the
viewport minus the fixed columns, the leading controls, and any frozen section, with
minColumnWidth as the floor when the fixed columns already overflow.

⚠️ Tables that declared a width on every column are unaffected. Tables that mixed the two will get
wider — and visible — weighted columns where they previously rendered nothing.

Also in this release

  • A test suite covering sorting, selection, pagination, keyboard navigation, tab order, column
    widths, and header-tree validation. The sort-cycle bug above is the one it found first.
  • Built against Compose Multiplatform 1.11.1, up from 1.9.2. Compose is an api dependency, so
    Gradle will resolve your project's Compose artifacts up to 1.11.1 unless you constrain them.
  • The documented requirements were wrong and are now correct. The artifact targets Java 11,
    not the "JVM 21+" the docs claimed; Kotlin metadata is emitted at language level 2.2. Nothing
    about the published bytecode changed — only the claim about it.
  • Documentation: keyboard shortcuts render as keycaps instead of literal ++ctrl++ text, and
    the site now states plainly
    what the table does not do
    cell editing, cell selection, clipboard, filtering, export, column reordering, layout
    persistence, tree tables, and accessibility semantics are all absent.
  • Demo packages for the sample gallery are attached below.

Links

Full Changelog: 0.3.0...0.4.0

0.3.0

Choose a tag to compare

@stephenWanjala stephenWanjala released this 16 Aug 18:37
c1874e5

What's Changed

No signatures changed, so 0.3.0 compiles against 0.2.0 call sites untouched. Three behaviour
changes are worth checking.

Sorting and pagination are properly controlled

Supplying onSortChange, onMultiSortChange, or onPageChange now makes that piece of state
controlled: the table renders the parameter and never changes it on its own.

In 0.2.0 the table kept an internal copy that it updated on interaction regardless, so a caller
who passed the callback but ignored the parameter still saw sorting work. That now does nothing
visible — the click fires the callback, and the table waits for you to feed the value back:

// Broken in 0.3.0: the callback fires, but sortBy never changes
DataTable(
    sortBy = SortState(),                     // constant!
    onSortChange = { analytics.track(it) },
)

// Correct: hoist it
var sort by remember { mutableStateOf(SortState()) }
DataTable(
    sortBy = sort,
    onSortChange = { sort = it; analytics.track(it) },
)

Passing no callback is unchanged — the table owns the state, and click-to-sort works with no wiring.

Nested headers render

DataTableHeader.children was accepted and silently ignored in every version up to 0.2.0. If you
set it, expecting nothing, you now get a grouped header; both throw rather
than misrender.

Misconfigured frozen columns throw

fixed = true without a width used to be quietly demoted to a normal scrolling column. It now
throws with a message naming the column. If pinning appeared not to work for you before, this is
why, and the fix is to give the column an explicit width.

Also in this release

  • manualSorting, manualPagination, and totalItems for server-side data.
  • Reworked pagination footer: grouped controls, a divider above it, hover states, and a
    rows-per-page menu that opens upward instead of off the bottom of the window.
  • DataTableHeader and SortState are @Immutable, and Compose is exposed as api rather
    than implementation so consumers get it transitively.
  • Press-and-drag no longer pans the table horizontally; wheel and trackpad scrolling are
    unchanged. This also stops drags fighting the column resize handles.

Focus now stays on its row when the table is re-sorted, instead of holding a fixed position.
If the focused row leaves the view — filtered out, or on another page — the next arrow key
starts again from the first row.

Fixes that may change what you see

No API change needed for these, but the rendering differs:

  • Alternating row colors were offset by the total item count, flipping which rows were
    tinted on odd-sized lists. They now start correctly at the first row.
  • The keyboard focus indicator never appeared in any configuration. It now renders on the
    focused row, so a focusedRowBorder color you set in 0.1.x becomes visible for the first time.
  • Enter and Space acted on the wrong row when groupBy was set, because navigation walked
    the pre-grouping order. They now follow display order.
  • Arrow-key scrolling overshot when group headers or summaries were present.

Full Changelog: v0.2.0...0.3.0

v0.2.0

Choose a tag to compare

@stephenWanjala stephenWanjala released this 16 Aug 16:31
ee290db

Full Changelog: 0.1.1...v0.2.0

v0.1.1

Choose a tag to compare

@stephenWanjala stephenWanjala released this 10 Apr 20:33
bf65396

Release Notes — v0.1.1

New Features

Frozen/Pinned Columns
Columns marked with fixed = true and an explicit width are now pinned to the left edge of the table and remain visible during horizontal scrolling.

Multi-Column Sort
Ctrl+click column headers to sort by multiple columns simultaneously. Use the new multiSortBy and onMultiSortChange parameters alongside the existing single-sort API.

Column Resizing
Enable resizableColumns = true to let users drag column edges to resize. Use minColumnWidth to set a lower bound, and DataTableState.resetColumnWidths() to revert to defaults.

Keyboard Navigation
The table is now focusable and supports Arrow Up/Down to move between rows, Enter to trigger onRowClick, Space to toggle selection, and Home/End to jump to the first or last row.

Selection Modes
A new SelectionMode enum (NONE, SINGLE, MULTI) replaces the implicit multi-select behavior previously tied to showSelect. The showSelect parameter remains for backwards compatibility.

Right-Click Context Menu
New onRowContextMenu: (T, Offset) -> Unit callback fired on right-click, providing the item and the pointer position.

DataTableState
New state holder created via rememberDataTableState(). Supports programmatic animateScrollToItem(index) and resetColumnWidths().

Items-Per-Page Selector
The pagination footer now includes a page-size picker. Configure available options with itemsPerPageOptions and respond to changes via onItemsPerPageChange.


Enhancements

  • Alternating row colors — set colors.rowAlternate for zebra-striped rows.
  • Row hover highlight — set colors.hoveredRow for a mouse-over tint.
  • Focused row border — set colors.focusedRowBorder to highlight the keyboard-focused row.
  • Per-column text overflowDataTableHeader now accepts maxLines and overflow (TextOverflow) to control cell text truncation.
  • Custom sort comparator — set DataTableHeader.comparator to override the default Comparable-based sort for a column.
  • Column visibility toggle — set DataTableHeader.visible = false to hide a column without removing it from the header list.
  • Multi-sort takes precedence over single-sort when both are provided.

Bug Fixes

  • Global row index was not tracked correctly across groups, causing mismatched focus and selection highlights in grouped tables.
  • Horizontal scrollbar was duplicated (rendered for both header and body) when showScrollbars = true and frozen columns were not in use.

Breaking Changes

  • DataTableRow and DataTableHeaderRow now require selectionMode, rowIndex, isFocused, state, and onContextMenu parameters. If you are calling these internal composables directly, update your call sites.
  • TableDivider and enableTrackpadHorizontalScroll are now internal. They were previously private but accessible in the same module — direct external use is no longer supported.
    Full Changelog: 0.1.0...0.1.1

0.1.0

Choose a tag to compare

@stephenWanjala stephenWanjala released this 03 Nov 08:04
aa47183
  • Initial implementation of the DataTable component for Compose Desktop supporting features such as sorting, grouping, and pagination.