Data grid / foldkit-mixins-data-grid
Sixty seconds
ts
import { Schema } from 'effect'
import type { HtmlBuilder } from 'foldkit/html'
import { defineMessageUnion } from 'foldkit/message'
import { Bundle } from 'foldkit-bundle'
import { Columns, DataGrid, RowModel } from 'foldkit-data-grid'
import { Style } from 'foldkit-mixins'
import { DataGridView, GridStyle } from 'foldkit-mixins-data-grid'
interface Item {
readonly id: string
readonly name: string
}
const items: ReadonlyArray<Item> = [
{ id: 'a', name: 'Anchor' },
{ id: 'b', name: 'Bolt' },
]
const itemKey = (item: Item) => item.id
const columns = Columns.define<Item>()({
id: { header: 'Id', value: item => item.id, pinned: 'start', width: 96 },
name: { header: 'Name', value: item => item.name, width: 240 },
})
const Grid = DataGrid.make({ id: 'items', columns })
// The grid's state is one field of the application's Model.
const Placement = Bundle.declare(Grid.bundle, 'grid')
const Model = Schema.Struct({ ...Placement.fields })
type Model = typeof Model.Type
const Message = defineMessageUnion({ ...Placement.cases })
type Message = typeof Message.Type
const application = Bundle.assemble<Model, Message>()([
// A grid reports edits as an OutMessage; this one edits nothing, so it ignores them.
Bundle.parent({ Model, Message }).at(Placement, { onOut: Bundle.ignore }),
])
const ItemsGrid = DataGridView<Message>().define(Grid).pipe(Style.attach(GridStyle))
const rows = RowModel.fromArray(items, itemKey)
const view = (model: Model, h: HtmlBuilder<Message>) =>
ItemsGrid(
{
state: model.grid,
rows,
wrap: message => Placement.wrapper.make(message),
label: 'Items',
rowHeight: 32,
headerHeight: 36,
},
h,
)application.initial(...) and application.update() run the grid's state
like any other placement; view draws it. Give the grid a height with a
Style on root (height: '24rem', say): it is the scroll container.
DataGridView<Message>().define(Grid)is a SlotView for that grid. Its row and column types come from the grid, so a cell renderer and the focused cell are checked against them.stateis the placedDataGridModel. The view reads the focused cell, the viewport and the column state from it, and works out the window withVirtualGrid.window.rowsis the application's rows, in its order; the view draws them through the column state (Grid.project) and never sorts. Keep the rows model between renders, or the projection is rebuilt every time.wraplifts the grid's Messages into the application's: keys sendMoved(with the scroll that reveals the cell), a pressed cell sendsFocused, and the scroll container sendsMeasured.GridStyleis the default look, in thecomponentslayer.