tally-core as pure functions. A key press becomes an intent, an intent becomes a selection action, and a reducer turns the current state and an action into the next state. tally-react wires them to the DOM, and you can run them anywhere.
Selection state
Cell addresses are indexes into the visible rows and columns. Row selection uses keys, so selected rows survive sorting and filtering.
Actions
reduceSelection(state, action, geometry) applies one action. The geometry gives the row and column counts, the page size, and the key of the row at an index.
Targets are clamped to the grid, so moving past an edge stays on the edge.
headless.ts
Intents
keyboardIntent(key, state, geometry, options?) maps a key press to a GridIntent. While a cell is being edited, only Escape produces an intent. On macOS pass platform: 'mac' so the primary modifier is Command instead of Control.
Keyboard in React
Under
dir="rtl" Left and Right follow the screen, so Right moves to the previous column.
Handling intents
onIntent on <Tally> sees every keyboard and pointer intent before the grid does. Return true to consume it.
accounts.tsx