@box-kite/react 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -229,12 +229,12 @@ import DataGrid from '@box-kite/react/components/dataGrid';
229
229
 
230
230
  **DataGridProps**: `data`, `def`, `component` (default `'datagrid'`), `loading`, `filters` (predicate[]), `page`/`onPageChange`, `onSortChange`, `onServerStateChange` (`{ page, pageSize, sortColumn, sortDirection, columnFilters, globalFilterValue }`), `onSelectionChange` (`{ action, selectedRowKeys, affectedRowKeys, isAllSelected }`), `expandedRowKeys`/`onExpandedRowKeysChange`, `globalFilterValue`/`onGlobalFilterChange`, `columnFilters`/`onColumnFiltersChange`, `onCellEditsChange` (`edit`/`paste`/`clear`), `onRangeChange` (`(range, { reason })` with `select`/`extend`/`clear`; `range` is `{ startRow, endRow, columns, values() }` or `undefined`), `onPaste` (`{ range, applied, rejected, skipped }`, once per Ctrl+V).
231
231
 
232
- **GridDefinition**: `columns` (required), `rowKey`, `rowHeight` (px, default 48), `visibleRowsCount` (number/`'all'`), `showRowNumber` (bool/`{ pinned?, width? }`), `rowSelection` (bool/`{ pinned? }`), `rowDetail` (`{ content, height?, expandOnRowClick?, pinned?, expandColumnWidth?, expandColumnHeader? }`), `pagination` (`{ totalCount, pageSize? }`), `topBar`/`bottomBar`, `title`/`topBarContent`, `globalFilter`, `globalFilterKeys`, `sortable`/`resizable` (default true), `contextMenu` (bool/`{ sort?, pin?, group? }`, default true), `resizerStyle` (`'visible'`/`'hover'`/`'hidden'`), `noDataComponent`, `editable`/`onCellEdit`, `tabNavigation` (`'none'` default — APG's single tab stop — or `'cells'`, the spreadsheet reading), `rangeSelection` (a drag or Shift+arrow marks a block of cells; `Ctrl+C` copies it as TSV and `Ctrl+V` fills it back through `onCellEdit`, one judgement per cell — both need no opt-in for the current cell alone).
232
+ **GridDefinition**: `columns` (required), `rowKey`, `rowHeight` (px, default 48), `visibleRowsCount` (number/`'all'`), `showRowNumber` (bool/`{ pinned?, width? }`), `rowSelection` (bool/`{ pinned? }` — the header checkbox acts on the rows the filters leave on screen, and the bottom bar counts selected rows the filters hide, with Show selected and Clear selection), `rowDetail` (`{ content, height?, expandOnRowClick?, pinned?, expandColumnWidth?, expandColumnHeader? }`), `pagination` (`{ totalCount, pageSize? }`), `topBar`/`bottomBar`, `title`/`topBarContent`, `globalFilter`, `globalFilterKeys`, `sortable`/`resizable` (default true), `contextMenu` (bool/`{ sort?, pin?, group? }`, default true), `resizerStyle` (`'visible'`/`'hover'`/`'hidden'`), `headerHover` (`'static'` — an inset pill per sortable cell — or `'sliding'`, one pill that flows between cells), `localeText` (any subset of `DataGridLocaleText` — every word the grid writes, for a translation; values with a number or a name in them are functions, and `DATA_GRID_LOCALE_TEXT` is the English to spread over), `noDataComponent`, `editable`/`onCellEdit`, `tabNavigation` (`'none'` default — APG's single tab stop — or `'cells'`, the spreadsheet reading), `rangeSelection` (a drag or Shift+arrow marks a block of cells; `Ctrl+C` copies it as TSV and `Ctrl+V` fills it back through `onCellEdit`, one judgement per cell — both need no opt-in for the current cell alone).
233
233
 
234
234
  **ColumnType**: `key`, `header`, `width` (px, default 200), `align` (`'start'`/`'end'`/`'center'`, or the physical `'left'`/`'right'`), `pin` (`'START'`/`'END'` — an edge of the **inline axis**, so a pinned column holds under either `dir`; `'LEFT'`/`'RIGHT'` are the older spelling of the same two), `columns` (grouped headers), `Cell` (`({ cell }) => ReactNode`), `sortable`/`resizable` (override grid), `flexible`, `filterable` (`true`=text, `{ type: 'number' }`, `{ type: 'multiselect' }`), `contextMenu` (override grid).
235
235
 
236
236
  **Server-side**: `def={{ pagination: { totalCount }, bottomBar: true }}` + `page={page}` + `onServerStateChange={fetchData}`.
237
237
 
238
- **Accessibility (A7, A10)**: the APG grid pattern, over a virtualized body — supplied whole, so add no roles and no `tabIndex`. The scrolling element is `role="grid"` (header and body are `rowgroup`s, rows `role="row"`, cells `role="gridcell"`/`columnheader`, scroll spacers `presentation`). `aria-rowcount`/`-colcount` describe the _whole_ grid and `aria-rowindex`/`-colindex` place each rendered cell in it, header rows first. Also `aria-sort` on sortable headers, `aria-selected` on rows only with `rowSelection`, `aria-busy` while `loading`, `aria-expanded` on group and expanded rows, and a live region announcing the selection count. Keyboard: one cell in the tab order; arrows move it, Home/End along the row, Ctrl+Home/End to the corners (scrolling to unrendered rows), PageUp/Down by a screenful, Enter/Space sorts a header or steps into the cell’s control, F2 always steps in, Escape steps back out. Down/Up keep the _column_ rather than the cell ordinal, so they land under where they started even through a grouped header. The column resizer is APG's window splitter — `role="separator"` with `aria-valuenow`/`-valuemin`/`-valuemax` in pixels; Tab or F2 reaches it, the arrows move it 16px, Home/End go to the narrowest the grid allows and to the grid's own width. Space on any cell selects its row, and on the header cell the select-all box sits in it toggles all of them. Every cell carries the **current-cell mark**, which survives the grid losing focus so `Ctrl+C` has something to act on; with `def.rangeSelection` the cells of a marked block carry `aria-selected` and the grid is `aria-multiselectable`, while a lone current cell carries neither. Every control the grid draws names itself after what it acts on ("Select row 4", "Column options for Age"); the column menu is the APG menu button. **Give it `def.title`** — a grid is not named by its rows. Every widget a cell holds is out of the page tab sequence, so the grid is one tab stop: Enter or F2 steps in, Tab walks the widgets **within that cell** and wraps, and Escape is the way out.
238
+ **Accessibility (A7, A10)**: the APG grid pattern, over a virtualized body — supplied whole, so add no roles and no `tabIndex`. The scrolling element is `role="grid"` (header and body are `rowgroup`s, rows `role="row"`, cells `role="gridcell"`/`columnheader`, scroll spacers `presentation`). `aria-rowcount`/`-colcount` describe the _whole_ grid and `aria-rowindex`/`-colindex` place each rendered cell in it, header rows first. Also `aria-sort` on sortable headers, `aria-selected` on rows only with `rowSelection`, `aria-busy` while `loading`, `aria-expanded` on group and expanded rows, and a live region announcing the selection count. Keyboard: one cell in the tab order; arrows move it, Home/End along the row, Ctrl+Home/End to the corners (scrolling to unrendered rows), PageUp/Down by a screenful, Enter/Space sorts a header or steps into the cell’s control, F2 always steps in, Escape steps back out. Down/Up keep the _column_ rather than the cell ordinal, so they land under where they started even through a grouped header. The column resizer is APG's window splitter — `role="separator"` with `aria-valuenow`/`-valuemin`/`-valuemax` in pixels; Tab or F2 reaches it, the arrows move it 16px, Home/End go to the narrowest the grid allows and to the grid's own width. Space on any cell selects its row, and on the header cell the select-all box sits in it toggles every row the filters leave on screen. Every cell carries the **current-cell mark**, which survives the grid losing focus so `Ctrl+C` has something to act on; with `def.rangeSelection` the cells of a marked block carry `aria-selected` and the grid is `aria-multiselectable`, while a lone current cell carries neither. Every control the grid draws names itself after what it acts on ("Select row 4", "Column options for Age"); the column menu is the APG menu button. **Give it `def.title`** — a grid is not named by its rows. Every widget a cell holds is out of the page tab sequence, so the grid is one tab stop: Enter or F2 steps in, Tab walks the widgets **within that cell** and wraps, and Escape is the way out.
239
239
 
240
240
  **Style tree**: `datagrid` > `content`, `topBar` > (`globalFilter` > `stats`, `columnGroups` > `icon`|`separator`|`item` > `icon`, `columnVisibility` > `badge`), `filter` > `cell` > `input`, `header` > `cell` > (`contextMenu` > `icon`|`tooltip` > `item` > `icon`|`separator`, `resizer`), `body` > (`cell` > `text`|`rowDetail`, `row`, `groupRow` > `expandButton`, `detailRow`, `empty`), `emptyColumns`, `bottomBar` > (`info`, `clearFilters`, `pagination` > `button`|`info`).
package/BOX_AI_CONTEXT.md CHANGED
@@ -2365,34 +2365,36 @@ named ones carry the reason.
2365
2365
 
2366
2366
  ### GridDefinition
2367
2367
 
2368
- | Prop | Type | Default | Description |
2369
- | ------------------------- | ------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
2370
- | `columns` | `ColumnType[]` | required | Column definitions |
2371
- | `rowKey` | `keyof TRow \| (row) => Key` | auto | Unique row identifier |
2372
- | `rowHeight` | `number` | `48` | Row height in px |
2373
- | `visibleRowsCount` | `number \| 'all'` | `10` | Visible rows. `'all'` disables virtualization |
2374
- | `showRowNumber` | `boolean \| { pinned?, width? }` | `false` | Row number column |
2375
- | `rowSelection` | `boolean \| { pinned? }` | `false` | Checkbox selection column |
2376
- | `rowDetail` | `RowDetailConfig` | — | Expandable detail panel (see below) |
2377
- | `treeData` | `TreeDataConfig` | — | Rows that hold rows: a `treegrid` with a chevron column (see below) |
2378
- | `groupBy` | `Key[]` | — | The columns the grid starts grouped by, outermost first. The column menu takes it from there |
2379
- | `groupDefaultExpanded` | `boolean \| number` | `false` | Which group rows start open: `true` for all, a number for how many levels down |
2380
- | `editable` | `boolean` | `false` | Whether every column can be edited. A column’s own `editable` takes priority |
2381
- | `onCellEdit` | `(edit) => void \| boolean \| string` | — | Judges an edit and is told about it: nothing accepts, a string refuses. May be async |
2382
- | `dataSource` | `DataSource` | — | The grid fetches its own rows a block at a time; `data` is not read at all |
2383
- | `pagination` | `{ totalCount, pageSize? }` | — | Server-side pagination. Bypasses client-side filtering |
2384
- | `topBar` / `bottomBar` | `boolean` | `false` | Show top/bottom bars |
2385
- | `title` / `topBarContent` | `ReactNode` | — | Top bar content |
2386
- | `globalFilter` | `boolean` | `false` | Enable global fuzzy search |
2387
- | `globalFilterKeys` | `(keyof TRow)[]` | all | Limit global filter columns |
2388
- | `sortable` / `resizable` | `boolean` | `true` | Enable sorting/resizing for all columns |
2389
- | `contextMenu` | `boolean \| ContextMenuConfig` | `true` | Control column header context menu. `false` hides it. Object: `{ sort?, pin?, group? }` |
2390
- | `resizerStyle` | `'visible' \| 'hover' \| 'hidden'` | `'visible'` | Resizer handle visibility. `'hover'`: shows on header cell hover. `'hidden'`: invisible but resize still works |
2391
- | `noDataComponent` | `ReactNode` | `'empty'` | Custom empty state |
2392
- | `footer` | `boolean \| { label? }` | `false` | A pinned row of grand totals over every column with an `aggregate`. `label` replaces the default `Total` |
2393
- | `export` | `boolean \| ExportConfig` | `false` | Export buttons in the top bar: `{ csv?, xlsx?, fileName? }`. The writers load on the first press |
2394
- | `tabNavigation` | `'none' \| 'cells'` | `'none'` | What Tab does. `'none'` is APG's single tab stop; `'cells'` is the spreadsheet reading |
2395
- | `rangeSelection` | `boolean` | `false` | A drag or Shift+arrow marks a block of cells, and `Ctrl+C`/`Ctrl+V` copy and paste it as TSV (see below) |
2368
+ | Prop | Type | Default | Description |
2369
+ | ------------------------- | ------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2370
+ | `columns` | `ColumnType[]` | required | Column definitions |
2371
+ | `rowKey` | `keyof TRow \| (row) => Key` | auto | Unique row identifier |
2372
+ | `rowHeight` | `number` | `48` | Row height in px |
2373
+ | `visibleRowsCount` | `number \| 'all'` | `10` | Visible rows. `'all'` disables virtualization |
2374
+ | `showRowNumber` | `boolean \| { pinned?, width? }` | `false` | Row number column |
2375
+ | `rowSelection` | `boolean \| { pinned? }` | `false` | Checkbox selection column. The header checkbox acts on the rows the filters leave on screen; a filter never drops a selection, and the bottom bar counts what it hides, with **Show selected** and **Clear selection** |
2376
+ | `rowDetail` | `RowDetailConfig` | — | Expandable detail panel (see below) |
2377
+ | `treeData` | `TreeDataConfig` | — | Rows that hold rows: a `treegrid` with a chevron column (see below) |
2378
+ | `groupBy` | `Key[]` | — | The columns the grid starts grouped by, outermost first. The column menu takes it from there |
2379
+ | `groupDefaultExpanded` | `boolean \| number` | `false` | Which group rows start open: `true` for all, a number for how many levels down |
2380
+ | `editable` | `boolean` | `false` | Whether every column can be edited. A column’s own `editable` takes priority |
2381
+ | `onCellEdit` | `(edit) => void \| boolean \| string` | — | Judges an edit and is told about it: nothing accepts, a string refuses. May be async |
2382
+ | `dataSource` | `DataSource` | — | The grid fetches its own rows a block at a time; `data` is not read at all |
2383
+ | `pagination` | `{ totalCount, pageSize? }` | — | Server-side pagination. Bypasses client-side filtering |
2384
+ | `topBar` / `bottomBar` | `boolean` | `false` | Show top/bottom bars |
2385
+ | `title` / `topBarContent` | `ReactNode` | — | Top bar content |
2386
+ | `globalFilter` | `boolean` | `false` | Enable global fuzzy search |
2387
+ | `globalFilterKeys` | `(keyof TRow)[]` | all | Limit global filter columns |
2388
+ | `sortable` / `resizable` | `boolean` | `true` | Enable sorting/resizing for all columns |
2389
+ | `contextMenu` | `boolean \| ContextMenuConfig` | `true` | Control column header context menu. `false` hides it. Object: `{ sort?, pin?, group? }` |
2390
+ | `resizerStyle` | `'visible' \| 'hover' \| 'hidden'` | `'visible'` | Resizer handle visibility. `'hover'`: shows on header cell hover. `'hidden'`: invisible but resize still works |
2391
+ | `headerHover` | `'static' \| 'sliding'` | `'static'` | Header hover: an inset pill per sortable cell, or one pill that flows from cell to cell. Whole cell sorts on press |
2392
+ | `localeText` | `Partial<DataGridLocaleText>` | English | Every word the grid writes — labels, accessible names, announcements, messages. Values with a number or a name in them are functions; spread `DATA_GRID_LOCALE_TEXT` to start a translation |
2393
+ | `noDataComponent` | `ReactNode` | `'empty'` | Custom empty state |
2394
+ | `footer` | `boolean \| { label? }` | `false` | A pinned row of grand totals over every column with an `aggregate`. `label` replaces the default `Total` |
2395
+ | `export` | `boolean \| ExportConfig` | `false` | Export buttons in the top bar: `{ csv?, xlsx?, fileName? }`. The writers load on the first press |
2396
+ | `tabNavigation` | `'none' \| 'cells'` | `'none'` | What Tab does. `'none'` is APG's single tab stop; `'cells'` is the spreadsheet reading |
2397
+ | `rangeSelection` | `boolean` | `false` | A drag or Shift+arrow marks a block of cells, and `Ctrl+C`/`Ctrl+V` copy and paste it as TSV (see below) |
2396
2398
 
2397
2399
  ### ColumnType
2398
2400
 
@@ -2404,7 +2406,7 @@ named ones carry the reason.
2404
2406
  | `align` | `'start' \| 'end' \| 'center' \| 'left' \| 'right'` | `'left'` | Cell alignment. `start`/`end` follow the reading order; `left`/`right` stay on the screen side they name |
2405
2407
  | `pin` | `'START' \| 'END'` (also `'LEFT'`/`'RIGHT'`) | — | Pin to an edge of the **inline axis** (sticky on scroll), so it holds under either `dir`. `LEFT`/`RIGHT` are the older spelling of the same two |
2406
2408
  | `columns` | `ColumnType[]` | — | Nested columns (grouped header) |
2407
- | `Cell` | `({ cell }) => ReactNode` | — | Custom renderer. `cell`: `{ value, row, column, grid }` |
2409
+ | `Cell` | `({ cell }) => ReactNode` | — | Custom renderer. `cell`: `{ value, row, column, grid }`. It redraws when its row changes or the grid does — not when another row is selected |
2408
2410
  | `sortable` / `resizable` | `boolean` | inherits | Override grid-level setting |
2409
2411
  | `flexible` | `boolean` | `true` | Participate in flex width distribution |
2410
2412
  | `filterable` | `boolean \| FilterConfig` | — | `true` (text), `{ type: 'number', min?, max? }`, `{ type: 'multiselect', options? }` |
@@ -2787,52 +2789,54 @@ stops, as they were before A7.
2787
2789
 
2788
2790
  ### Component Style Tree
2789
2791
 
2790
- | Component Name | Description | Variants |
2791
- | --------------------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2792
- | `datagrid` | Root container | — |
2793
- | `datagrid.content` | Scroll container for header + body | — |
2794
- | `datagrid.topBar` | Top bar (title, filters, column groups) | — |
2795
- | `datagrid.topBar.globalFilter` | Global search wrapper | — |
2796
- | `datagrid.topBar.globalFilter.stats` | Filtered rows count badge | — |
2797
- | `datagrid.topBar.columnGroups` | Column group chips container | — |
2798
- | `datagrid.topBar.columnGroups.icon` | Column group icon | — |
2799
- | `datagrid.topBar.columnGroups.separator` | Separator between groups | — |
2800
- | `datagrid.topBar.columnGroups.item` | Column group chip | — |
2801
- | `datagrid.topBar.columnGroups.item.icon` | Remove icon on chip | — |
2802
- | `datagrid.topBar.columnVisibility` | Column visibility dropdown | — |
2803
- | `datagrid.topBar.columnVisibility.badge` | Hidden columns count badge | — |
2804
- | `datagrid.filter.cell` | Filter row cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned` |
2805
- | `datagrid.filter.cell.input` | Filter input container (text/number/multiselect) | — |
2806
- | `datagrid.header` | Header grid container (sticky) | — |
2807
- | `datagrid.header.cell` | Header cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isSortable`, `isRowSelection`, `isRowNumber`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell` |
2808
- | `datagrid.header.cell.contextMenu` | Column context menu button | — |
2809
- | `datagrid.header.cell.contextMenu.icon` | Context menu icon | — |
2810
- | `datagrid.header.cell.contextMenu.tooltip` | Context menu popup | — |
2811
- | `datagrid.header.cell.contextMenu.tooltip.item` | Context menu action | — |
2812
- | `datagrid.header.cell.contextMenu.tooltip.item.icon` | Action icon | — |
2813
- | `datagrid.header.cell.contextMenu.tooltip.item.separator` | Menu separator line | — |
2814
- | `datagrid.header.cell.resizer` | Column resize handle | — |
2815
- | `datagrid.body` | Body grid container (virtualized rows) | — |
2816
- | `datagrid.body.cell` | Body cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isRowNumber`, `isRowSelection`, `isRowSelected`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell`, `isEditing`, `isInvalid` |
2817
- | `datagrid.body.cell.text` | Default cell text renderer | — |
2818
- | `datagrid.body.cell.editor` | The open cell editor | `isPending` |
2819
- | `datagrid.body.cell.error` | What a refused value says, in the top layer | — |
2820
- | `datagrid.body.cell.rowDetail` | Row detail expand/collapse button | — |
2821
- | `datagrid.body.cell.tree` | Tree cell: the indent, the chevron and the value | — |
2822
- | `datagrid.body.cell.tree.toggle` | Tree expand/collapse chevron | `isExpanded` |
2823
- | `datagrid.body.cell.tree.spacer` | What a leaf puts where its chevron would be | — |
2824
- | `datagrid.body.row` | Data row (display: contents) | — |
2825
- | `datagrid.body.groupRow` | Group row (display: contents) | — |
2826
- | `datagrid.body.groupRow.expandButton` | Group expand/collapse button | — |
2827
- | `datagrid.body.detailRow` | Expanded detail row | — |
2828
- | `datagrid.body.empty` | Empty state container | — |
2829
- | `datagrid.emptyColumns` | No columns selected placeholder | — |
2830
- | `datagrid.bottomBar` | Bottom bar (row count, pagination) | — |
2831
- | `datagrid.bottomBar.info` | Status text ("Rows: ...", "Selected: ...") | — |
2832
- | `datagrid.bottomBar.clearFilters` | "Clear filters" link | — |
2833
- | `datagrid.bottomBar.pagination` | Pagination controls wrapper | — |
2834
- | `datagrid.bottomBar.pagination.button` | Pagination nav button | — |
2835
- | `datagrid.bottomBar.pagination.info` | Page info text ("1 of 5") | — |
2792
+ | Component Name | Description | Variants |
2793
+ | --------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2794
+ | `datagrid` | Root container | — |
2795
+ | `datagrid.content` | Scroll container for header + body | — |
2796
+ | `datagrid.topBar` | Top bar (title, filters, column groups) | — |
2797
+ | `datagrid.topBar.globalFilter` | Global search wrapper | — |
2798
+ | `datagrid.topBar.globalFilter.stats` | Filtered rows count badge (only without a bottom bar) | — |
2799
+ | `datagrid.topBar.columnGroups` | Column group chips container | — |
2800
+ | `datagrid.topBar.columnGroups.icon` | Column group icon | — |
2801
+ | `datagrid.topBar.columnGroups.separator` | Separator between groups | — |
2802
+ | `datagrid.topBar.columnGroups.item` | Column group chip | — |
2803
+ | `datagrid.topBar.columnGroups.item.icon` | Remove icon on chip | — |
2804
+ | `datagrid.topBar.columnVisibility` | Column visibility dropdown | — |
2805
+ | `datagrid.topBar.columnVisibility.badge` | Hidden columns count badge | — |
2806
+ | `datagrid.filter.cell` | Filter row cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned` |
2807
+ | `datagrid.filter.cell.input` | Filter input container (text/number/multiselect) | — |
2808
+ | `datagrid.header` | Header grid container (sticky) | — |
2809
+ | `datagrid.header.cell` | Header cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isSortable`, `isRowSelection`, `isRowNumber`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell` |
2810
+ | `datagrid.header.cell.contextMenu` | Column context menu button | — |
2811
+ | `datagrid.header.cell.contextMenu.icon` | Context menu icon | — |
2812
+ | `datagrid.header.cell.contextMenu.tooltip` | Context menu popup | — |
2813
+ | `datagrid.header.cell.contextMenu.tooltip.item` | Context menu action | — |
2814
+ | `datagrid.header.cell.contextMenu.tooltip.item.icon` | Action icon | — |
2815
+ | `datagrid.header.cell.contextMenu.tooltip.item.separator` | Menu separator line | — |
2816
+ | `datagrid.header.cell.resizer` | Column resize handle | — |
2817
+ | `datagrid.body` | Body grid container (virtualized rows) | — |
2818
+ | `datagrid.body.cell` | Body cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isRowNumber`, `isRowSelection`, `isRowSelected`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell`, `isEditing`, `isInvalid` |
2819
+ | `datagrid.body.cell.text` | Default cell text renderer | — |
2820
+ | `datagrid.body.cell.editor` | The open cell editor | `isPending` |
2821
+ | `datagrid.body.cell.error` | What a refused value says, in the top layer | — |
2822
+ | `datagrid.body.cell.rowDetail` | Row detail expand/collapse button | — |
2823
+ | `datagrid.body.cell.tree` | Tree cell: the indent, the chevron and the value | — |
2824
+ | `datagrid.body.cell.tree.toggle` | Tree expand/collapse chevron | `isExpanded` |
2825
+ | `datagrid.body.cell.tree.spacer` | What a leaf puts where its chevron would be | — |
2826
+ | `datagrid.body.row` | Data row (display: contents) | — |
2827
+ | `datagrid.body.groupRow` | Group row (display: contents) | — |
2828
+ | `datagrid.body.groupRow.expandButton` | Group expand/collapse button | — |
2829
+ | `datagrid.body.detailRow` | Expanded detail row | — |
2830
+ | `datagrid.body.empty` | Empty state container | — |
2831
+ | `datagrid.emptyColumns` | No columns selected placeholder | — |
2832
+ | `datagrid.bottomBar` | Bottom bar (row count, pagination) | — |
2833
+ | `datagrid.bottomBar.info` | Status text ("Rows: ...", "Selected: ...") | — |
2834
+ | `datagrid.bottomBar.clearFilters` | "Clear filters" button | — |
2835
+ | `datagrid.bottomBar.selection` | The selection count and its buttons, at the bar's far end | — |
2836
+ | `datagrid.bottomBar.action` | "Show selected" and "Clear selection" | `pressed` (Show selected while it is on) |
2837
+ | `datagrid.bottomBar.pagination` | Pagination controls wrapper | — |
2838
+ | `datagrid.bottomBar.pagination.button` | Pagination nav button | — |
2839
+ | `datagrid.bottomBar.pagination.info` | Page info text ("1 of 5") | — |
2836
2840
 
2837
2841
  ---
2838
2842
 
@@ -2365,34 +2365,36 @@ named ones carry the reason.
2365
2365
 
2366
2366
  ### GridDefinition
2367
2367
 
2368
- | Prop | Type | Default | Description |
2369
- | ------------------------- | ------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
2370
- | `columns` | `ColumnType[]` | required | Column definitions |
2371
- | `rowKey` | `keyof TRow \| (row) => Key` | auto | Unique row identifier |
2372
- | `rowHeight` | `number` | `48` | Row height in px |
2373
- | `visibleRowsCount` | `number \| 'all'` | `10` | Visible rows. `'all'` disables virtualization |
2374
- | `showRowNumber` | `boolean \| { pinned?, width? }` | `false` | Row number column |
2375
- | `rowSelection` | `boolean \| { pinned? }` | `false` | Checkbox selection column |
2376
- | `rowDetail` | `RowDetailConfig` | — | Expandable detail panel (see below) |
2377
- | `treeData` | `TreeDataConfig` | — | Rows that hold rows: a `treegrid` with a chevron column (see below) |
2378
- | `groupBy` | `Key[]` | — | The columns the grid starts grouped by, outermost first. The column menu takes it from there |
2379
- | `groupDefaultExpanded` | `boolean \| number` | `false` | Which group rows start open: `true` for all, a number for how many levels down |
2380
- | `editable` | `boolean` | `false` | Whether every column can be edited. A column’s own `editable` takes priority |
2381
- | `onCellEdit` | `(edit) => void \| boolean \| string` | — | Judges an edit and is told about it: nothing accepts, a string refuses. May be async |
2382
- | `dataSource` | `DataSource` | — | The grid fetches its own rows a block at a time; `data` is not read at all |
2383
- | `pagination` | `{ totalCount, pageSize? }` | — | Server-side pagination. Bypasses client-side filtering |
2384
- | `topBar` / `bottomBar` | `boolean` | `false` | Show top/bottom bars |
2385
- | `title` / `topBarContent` | `ReactNode` | — | Top bar content |
2386
- | `globalFilter` | `boolean` | `false` | Enable global fuzzy search |
2387
- | `globalFilterKeys` | `(keyof TRow)[]` | all | Limit global filter columns |
2388
- | `sortable` / `resizable` | `boolean` | `true` | Enable sorting/resizing for all columns |
2389
- | `contextMenu` | `boolean \| ContextMenuConfig` | `true` | Control column header context menu. `false` hides it. Object: `{ sort?, pin?, group? }` |
2390
- | `resizerStyle` | `'visible' \| 'hover' \| 'hidden'` | `'visible'` | Resizer handle visibility. `'hover'`: shows on header cell hover. `'hidden'`: invisible but resize still works |
2391
- | `noDataComponent` | `ReactNode` | `'empty'` | Custom empty state |
2392
- | `footer` | `boolean \| { label? }` | `false` | A pinned row of grand totals over every column with an `aggregate`. `label` replaces the default `Total` |
2393
- | `export` | `boolean \| ExportConfig` | `false` | Export buttons in the top bar: `{ csv?, xlsx?, fileName? }`. The writers load on the first press |
2394
- | `tabNavigation` | `'none' \| 'cells'` | `'none'` | What Tab does. `'none'` is APG's single tab stop; `'cells'` is the spreadsheet reading |
2395
- | `rangeSelection` | `boolean` | `false` | A drag or Shift+arrow marks a block of cells, and `Ctrl+C`/`Ctrl+V` copy and paste it as TSV (see below) |
2368
+ | Prop | Type | Default | Description |
2369
+ | ------------------------- | ------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2370
+ | `columns` | `ColumnType[]` | required | Column definitions |
2371
+ | `rowKey` | `keyof TRow \| (row) => Key` | auto | Unique row identifier |
2372
+ | `rowHeight` | `number` | `48` | Row height in px |
2373
+ | `visibleRowsCount` | `number \| 'all'` | `10` | Visible rows. `'all'` disables virtualization |
2374
+ | `showRowNumber` | `boolean \| { pinned?, width? }` | `false` | Row number column |
2375
+ | `rowSelection` | `boolean \| { pinned? }` | `false` | Checkbox selection column. The header checkbox acts on the rows the filters leave on screen; a filter never drops a selection, and the bottom bar counts what it hides, with **Show selected** and **Clear selection** |
2376
+ | `rowDetail` | `RowDetailConfig` | — | Expandable detail panel (see below) |
2377
+ | `treeData` | `TreeDataConfig` | — | Rows that hold rows: a `treegrid` with a chevron column (see below) |
2378
+ | `groupBy` | `Key[]` | — | The columns the grid starts grouped by, outermost first. The column menu takes it from there |
2379
+ | `groupDefaultExpanded` | `boolean \| number` | `false` | Which group rows start open: `true` for all, a number for how many levels down |
2380
+ | `editable` | `boolean` | `false` | Whether every column can be edited. A column’s own `editable` takes priority |
2381
+ | `onCellEdit` | `(edit) => void \| boolean \| string` | — | Judges an edit and is told about it: nothing accepts, a string refuses. May be async |
2382
+ | `dataSource` | `DataSource` | — | The grid fetches its own rows a block at a time; `data` is not read at all |
2383
+ | `pagination` | `{ totalCount, pageSize? }` | — | Server-side pagination. Bypasses client-side filtering |
2384
+ | `topBar` / `bottomBar` | `boolean` | `false` | Show top/bottom bars |
2385
+ | `title` / `topBarContent` | `ReactNode` | — | Top bar content |
2386
+ | `globalFilter` | `boolean` | `false` | Enable global fuzzy search |
2387
+ | `globalFilterKeys` | `(keyof TRow)[]` | all | Limit global filter columns |
2388
+ | `sortable` / `resizable` | `boolean` | `true` | Enable sorting/resizing for all columns |
2389
+ | `contextMenu` | `boolean \| ContextMenuConfig` | `true` | Control column header context menu. `false` hides it. Object: `{ sort?, pin?, group? }` |
2390
+ | `resizerStyle` | `'visible' \| 'hover' \| 'hidden'` | `'visible'` | Resizer handle visibility. `'hover'`: shows on header cell hover. `'hidden'`: invisible but resize still works |
2391
+ | `headerHover` | `'static' \| 'sliding'` | `'static'` | Header hover: an inset pill per sortable cell, or one pill that flows from cell to cell. Whole cell sorts on press |
2392
+ | `localeText` | `Partial<DataGridLocaleText>` | English | Every word the grid writes — labels, accessible names, announcements, messages. Values with a number or a name in them are functions; spread `DATA_GRID_LOCALE_TEXT` to start a translation |
2393
+ | `noDataComponent` | `ReactNode` | `'empty'` | Custom empty state |
2394
+ | `footer` | `boolean \| { label? }` | `false` | A pinned row of grand totals over every column with an `aggregate`. `label` replaces the default `Total` |
2395
+ | `export` | `boolean \| ExportConfig` | `false` | Export buttons in the top bar: `{ csv?, xlsx?, fileName? }`. The writers load on the first press |
2396
+ | `tabNavigation` | `'none' \| 'cells'` | `'none'` | What Tab does. `'none'` is APG's single tab stop; `'cells'` is the spreadsheet reading |
2397
+ | `rangeSelection` | `boolean` | `false` | A drag or Shift+arrow marks a block of cells, and `Ctrl+C`/`Ctrl+V` copy and paste it as TSV (see below) |
2396
2398
 
2397
2399
  ### ColumnType
2398
2400
 
@@ -2404,7 +2406,7 @@ named ones carry the reason.
2404
2406
  | `align` | `'start' \| 'end' \| 'center' \| 'left' \| 'right'` | `'left'` | Cell alignment. `start`/`end` follow the reading order; `left`/`right` stay on the screen side they name |
2405
2407
  | `pin` | `'START' \| 'END'` (also `'LEFT'`/`'RIGHT'`) | — | Pin to an edge of the **inline axis** (sticky on scroll), so it holds under either `dir`. `LEFT`/`RIGHT` are the older spelling of the same two |
2406
2408
  | `columns` | `ColumnType[]` | — | Nested columns (grouped header) |
2407
- | `Cell` | `({ cell }) => ReactNode` | — | Custom renderer. `cell`: `{ value, row, column, grid }` |
2409
+ | `Cell` | `({ cell }) => ReactNode` | — | Custom renderer. `cell`: `{ value, row, column, grid }`. It redraws when its row changes or the grid does — not when another row is selected |
2408
2410
  | `sortable` / `resizable` | `boolean` | inherits | Override grid-level setting |
2409
2411
  | `flexible` | `boolean` | `true` | Participate in flex width distribution |
2410
2412
  | `filterable` | `boolean \| FilterConfig` | — | `true` (text), `{ type: 'number', min?, max? }`, `{ type: 'multiselect', options? }` |
@@ -2787,52 +2789,54 @@ stops, as they were before A7.
2787
2789
 
2788
2790
  ### Component Style Tree
2789
2791
 
2790
- | Component Name | Description | Variants |
2791
- | --------------------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2792
- | `datagrid` | Root container | — |
2793
- | `datagrid.content` | Scroll container for header + body | — |
2794
- | `datagrid.topBar` | Top bar (title, filters, column groups) | — |
2795
- | `datagrid.topBar.globalFilter` | Global search wrapper | — |
2796
- | `datagrid.topBar.globalFilter.stats` | Filtered rows count badge | — |
2797
- | `datagrid.topBar.columnGroups` | Column group chips container | — |
2798
- | `datagrid.topBar.columnGroups.icon` | Column group icon | — |
2799
- | `datagrid.topBar.columnGroups.separator` | Separator between groups | — |
2800
- | `datagrid.topBar.columnGroups.item` | Column group chip | — |
2801
- | `datagrid.topBar.columnGroups.item.icon` | Remove icon on chip | — |
2802
- | `datagrid.topBar.columnVisibility` | Column visibility dropdown | — |
2803
- | `datagrid.topBar.columnVisibility.badge` | Hidden columns count badge | — |
2804
- | `datagrid.filter.cell` | Filter row cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned` |
2805
- | `datagrid.filter.cell.input` | Filter input container (text/number/multiselect) | — |
2806
- | `datagrid.header` | Header grid container (sticky) | — |
2807
- | `datagrid.header.cell` | Header cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isSortable`, `isRowSelection`, `isRowNumber`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell` |
2808
- | `datagrid.header.cell.contextMenu` | Column context menu button | — |
2809
- | `datagrid.header.cell.contextMenu.icon` | Context menu icon | — |
2810
- | `datagrid.header.cell.contextMenu.tooltip` | Context menu popup | — |
2811
- | `datagrid.header.cell.contextMenu.tooltip.item` | Context menu action | — |
2812
- | `datagrid.header.cell.contextMenu.tooltip.item.icon` | Action icon | — |
2813
- | `datagrid.header.cell.contextMenu.tooltip.item.separator` | Menu separator line | — |
2814
- | `datagrid.header.cell.resizer` | Column resize handle | — |
2815
- | `datagrid.body` | Body grid container (virtualized rows) | — |
2816
- | `datagrid.body.cell` | Body cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isRowNumber`, `isRowSelection`, `isRowSelected`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell`, `isEditing`, `isInvalid` |
2817
- | `datagrid.body.cell.text` | Default cell text renderer | — |
2818
- | `datagrid.body.cell.editor` | The open cell editor | `isPending` |
2819
- | `datagrid.body.cell.error` | What a refused value says, in the top layer | — |
2820
- | `datagrid.body.cell.rowDetail` | Row detail expand/collapse button | — |
2821
- | `datagrid.body.cell.tree` | Tree cell: the indent, the chevron and the value | — |
2822
- | `datagrid.body.cell.tree.toggle` | Tree expand/collapse chevron | `isExpanded` |
2823
- | `datagrid.body.cell.tree.spacer` | What a leaf puts where its chevron would be | — |
2824
- | `datagrid.body.row` | Data row (display: contents) | — |
2825
- | `datagrid.body.groupRow` | Group row (display: contents) | — |
2826
- | `datagrid.body.groupRow.expandButton` | Group expand/collapse button | — |
2827
- | `datagrid.body.detailRow` | Expanded detail row | — |
2828
- | `datagrid.body.empty` | Empty state container | — |
2829
- | `datagrid.emptyColumns` | No columns selected placeholder | — |
2830
- | `datagrid.bottomBar` | Bottom bar (row count, pagination) | — |
2831
- | `datagrid.bottomBar.info` | Status text ("Rows: ...", "Selected: ...") | — |
2832
- | `datagrid.bottomBar.clearFilters` | "Clear filters" link | — |
2833
- | `datagrid.bottomBar.pagination` | Pagination controls wrapper | — |
2834
- | `datagrid.bottomBar.pagination.button` | Pagination nav button | — |
2835
- | `datagrid.bottomBar.pagination.info` | Page info text ("1 of 5") | — |
2792
+ | Component Name | Description | Variants |
2793
+ | --------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2794
+ | `datagrid` | Root container | — |
2795
+ | `datagrid.content` | Scroll container for header + body | — |
2796
+ | `datagrid.topBar` | Top bar (title, filters, column groups) | — |
2797
+ | `datagrid.topBar.globalFilter` | Global search wrapper | — |
2798
+ | `datagrid.topBar.globalFilter.stats` | Filtered rows count badge (only without a bottom bar) | — |
2799
+ | `datagrid.topBar.columnGroups` | Column group chips container | — |
2800
+ | `datagrid.topBar.columnGroups.icon` | Column group icon | — |
2801
+ | `datagrid.topBar.columnGroups.separator` | Separator between groups | — |
2802
+ | `datagrid.topBar.columnGroups.item` | Column group chip | — |
2803
+ | `datagrid.topBar.columnGroups.item.icon` | Remove icon on chip | — |
2804
+ | `datagrid.topBar.columnVisibility` | Column visibility dropdown | — |
2805
+ | `datagrid.topBar.columnVisibility.badge` | Hidden columns count badge | — |
2806
+ | `datagrid.filter.cell` | Filter row cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned` |
2807
+ | `datagrid.filter.cell.input` | Filter input container (text/number/multiselect) | — |
2808
+ | `datagrid.header` | Header grid container (sticky) | — |
2809
+ | `datagrid.header.cell` | Header cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isSortable`, `isRowSelection`, `isRowNumber`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell` |
2810
+ | `datagrid.header.cell.contextMenu` | Column context menu button | — |
2811
+ | `datagrid.header.cell.contextMenu.icon` | Context menu icon | — |
2812
+ | `datagrid.header.cell.contextMenu.tooltip` | Context menu popup | — |
2813
+ | `datagrid.header.cell.contextMenu.tooltip.item` | Context menu action | — |
2814
+ | `datagrid.header.cell.contextMenu.tooltip.item.icon` | Action icon | — |
2815
+ | `datagrid.header.cell.contextMenu.tooltip.item.separator` | Menu separator line | — |
2816
+ | `datagrid.header.cell.resizer` | Column resize handle | — |
2817
+ | `datagrid.body` | Body grid container (virtualized rows) | — |
2818
+ | `datagrid.body.cell` | Body cell | `isPinned`, `isFirstLeftPinned`, `isLastLeftPinned`, `isFirstRightPinned`, `isLastRightPinned`, `isRowNumber`, `isRowSelection`, `isRowSelected`, `isFirstLeaf`, `isLastLeaf`, `isEmptyCell`, `isEditing`, `isInvalid` |
2819
+ | `datagrid.body.cell.text` | Default cell text renderer | — |
2820
+ | `datagrid.body.cell.editor` | The open cell editor | `isPending` |
2821
+ | `datagrid.body.cell.error` | What a refused value says, in the top layer | — |
2822
+ | `datagrid.body.cell.rowDetail` | Row detail expand/collapse button | — |
2823
+ | `datagrid.body.cell.tree` | Tree cell: the indent, the chevron and the value | — |
2824
+ | `datagrid.body.cell.tree.toggle` | Tree expand/collapse chevron | `isExpanded` |
2825
+ | `datagrid.body.cell.tree.spacer` | What a leaf puts where its chevron would be | — |
2826
+ | `datagrid.body.row` | Data row (display: contents) | — |
2827
+ | `datagrid.body.groupRow` | Group row (display: contents) | — |
2828
+ | `datagrid.body.groupRow.expandButton` | Group expand/collapse button | — |
2829
+ | `datagrid.body.detailRow` | Expanded detail row | — |
2830
+ | `datagrid.body.empty` | Empty state container | — |
2831
+ | `datagrid.emptyColumns` | No columns selected placeholder | — |
2832
+ | `datagrid.bottomBar` | Bottom bar (row count, pagination) | — |
2833
+ | `datagrid.bottomBar.info` | Status text ("Rows: ...", "Selected: ...") | — |
2834
+ | `datagrid.bottomBar.clearFilters` | "Clear filters" button | — |
2835
+ | `datagrid.bottomBar.selection` | The selection count and its buttons, at the bar's far end | — |
2836
+ | `datagrid.bottomBar.action` | "Show selected" and "Clear selection" | `pressed` (Show selected while it is on) |
2837
+ | `datagrid.bottomBar.pagination` | Pagination controls wrapper | — |
2838
+ | `datagrid.bottomBar.pagination.button` | Pagination nav button | — |
2839
+ | `datagrid.bottomBar.pagination.info` | Page info text ("1 of 5") | — |
2836
2840
 
2837
2841
  ---
2838
2842
 
package/README.md CHANGED
@@ -10,7 +10,7 @@ pass at runtime and caches every rule by its content, so the same value anywhere
10
10
  one class — a project styles itself in TypeScript, with no CSS files to write and no class-name
11
11
  convention to remember.
12
12
 
13
- [Docs and live demos](https://www.box-kite.dev) · [Contributing](CONTRIBUTING.md) ·
13
+ [Docs and live demos](https://www.box-kite.dev) · [Blog](https://www.box-kite.dev/blog/) · [Contributing](CONTRIBUTING.md) ·
14
14
  [Support](SUPPORT.md) · [Security](SECURITY.md) ·
15
15
  [Releases](https://github.com/box-kite/box-kite/releases)
16
16
 
@@ -0,0 +1,7 @@
1
+ import { default as GridModel } from '../models/gridModel';
2
+ interface Props<TRow> {
3
+ grid: GridModel<TRow>;
4
+ }
5
+ /** The selection's half of the bottom bar: the count, how much of it the filters hide, and the two ways out. */
6
+ export default function DataGridBottomBarSelection<TRow>(props: Props<TRow>): import("react").JSX.Element;
7
+ export {};
@@ -4,10 +4,10 @@ interface Props<TRow> {
4
4
  /** Position in the whole row list, not in the rendered window. */
5
5
  index: number;
6
6
  /**
7
- * The grid's store version. Not read: it is what tells the memo below that something the row draws
8
- * from the model has moved, since every other prop it takes holds still while the window slides.
7
+ * This row's version (`GridModel.rowVersion`). Not read: it is what tells the memo below that something
8
+ * the row draws from the model has moved, since every other prop it takes holds still while the window slides.
9
9
  */
10
- version: number;
10
+ version: string;
11
11
  }
12
12
  declare function DataGridDetailRowImpl<TRow>(props: Props<TRow>): import("react").JSX.Element;
13
13
  /**