Data grid / foldkit-data-grid
Focus
Focus is the grid's first piece of state: which cell is current, held in the Model by identity. Make it once per grid, then place its Bundle like any other.
ts
import { Option } from 'effect'
import { GridFocus } from 'foldkit-data-grid'
const Focus = GridFocus.make(columns)
// Focus.bundle is placed with foldkit-bundle; Focus.Model holds
// { current: Option<CellAddress> }, stored as null when nothing is focused.
const next = GridFocus.target(grid, {
current: Option.some({ row: 'p1', column: 'sku' }),
key: 'ArrowDown',
modifiers: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
pageRows: 10,
})
// Option.some({ row: 'p2', column: 'sku' }): dispatch Focus.Message.Focused with itGridFocus.make(columns)builds the Bundle, its Model and its one Message,Focused. The stored column is one of these columns' ids, so a saved focus naming a removed column fails to decode. Focusing the focused cell again returns the Model it was given.GridFocus.target(projection, options)is the cell a key moves to: arrows, Home and End (with Ctrl, the grid's corners), and PageUp and PageDown bypageRows. Underdirection: 'rtl'left and right swap. It returns none for a key the grid leaves to the page, such as Enter, Tab, or anything with Shift, Alt or Meta; a key it handles always lands somewhere, staying put at an edge or before a row that has not loaded.GridFocus.tabStop(projection, current)is the cell holding the grid's one tab stop: the focused cell while it is shown, else the first cell. A focused cell in a hidden column stays in the Model, so focus comes back when the column does.GridFocus.cellId(gridId, address)is a cell's DOM id, unique across cells whatever their keys hold. The grid keeps DOM focus on its container and points at the current cell witharia-activedescendant, so a cell can scroll out of a virtual window without losing focus.
foldkit-mixins-data-grid wires these keys
onto the drawn grid.