@box-kite/react 1.0.0 → 2.0.0

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.
Files changed (179) hide show
  1. package/.claude/rules/box-kite-rules.md +23 -1
  2. package/.claude/skills/box-kite/SKILL.md +134 -427
  3. package/.claude/skills/box-kite/references/components.md +235 -0
  4. package/.claude/skills/box-kite/references/extending.md +42 -0
  5. package/.claude/skills/box-kite/references/patterns.md +27 -0
  6. package/.claude/skills/box-kite/references/styling.md +222 -0
  7. package/.cursor/rules/box-kite.mdc +73 -0
  8. package/AGENTS.md +102 -0
  9. package/BOX_AI_CONTEXT.md +1124 -153
  10. package/BOX_KITE_AI_CONTEXT.md +1124 -153
  11. package/README.md +36 -2
  12. package/a11y.cjs +1 -1
  13. package/a11y.d.ts +1 -1
  14. package/a11y.mjs +3 -2
  15. package/anchor.cjs +1 -0
  16. package/anchor.d.ts +14 -0
  17. package/anchor.mjs +3 -0
  18. package/behavior.cjs +1 -1
  19. package/behavior.mjs +118 -136
  20. package/box.cjs +1 -1
  21. package/box.mjs +1 -1
  22. package/client.cjs +1 -1
  23. package/client.mjs +15 -14
  24. package/components/accordion.cjs +1 -0
  25. package/components/accordion.d.ts +114 -0
  26. package/components/accordion.mjs +251 -0
  27. package/components/button.cjs +1 -1
  28. package/components/button.d.ts +3 -0
  29. package/components/button.mjs +1 -1
  30. package/components/chart.cjs +1 -1
  31. package/components/chart.d.ts +2 -1
  32. package/components/chart.mjs +159 -184
  33. package/components/checkbox.cjs +1 -1
  34. package/components/checkbox.d.ts +8 -0
  35. package/components/checkbox.mjs +1 -1
  36. package/components/combobox/comboboxChips.d.ts +21 -0
  37. package/components/combobox/comboboxListbox.d.ts +47 -0
  38. package/components/combobox.cjs +1 -0
  39. package/components/combobox.d.ts +121 -0
  40. package/components/combobox.mjs +563 -0
  41. package/components/dataGrid/components/dataGridAggregateValue.d.ts +10 -0
  42. package/components/dataGrid/components/dataGridCell.d.ts +2 -1
  43. package/components/dataGrid/components/dataGridCellEditor.d.ts +15 -0
  44. package/components/dataGrid/components/dataGridCellPlaceholder.d.ts +14 -0
  45. package/components/dataGrid/components/dataGridCellTree.d.ts +16 -0
  46. package/components/dataGrid/components/dataGridDataSourceError.d.ts +12 -0
  47. package/components/dataGrid/components/dataGridExport.d.ts +10 -0
  48. package/components/dataGrid/components/dataGridFooter.d.ts +11 -0
  49. package/components/dataGrid/contracts/dataGridContract.d.ts +474 -16
  50. package/components/dataGrid/export/gridExport.d.ts +10 -0
  51. package/components/dataGrid/gridNavigationContext.d.ts +9 -1
  52. package/components/dataGrid/models/aggregateCellModel.d.ts +34 -0
  53. package/components/dataGrid/models/aggregationModel.d.ts +32 -0
  54. package/components/dataGrid/models/cellKeys.d.ts +11 -0
  55. package/components/dataGrid/models/cellModel.d.ts +27 -1
  56. package/components/dataGrid/models/columnModel.d.ts +12 -2
  57. package/components/dataGrid/models/dataSourceModel.d.ts +177 -0
  58. package/components/dataGrid/models/editModel.d.ts +77 -0
  59. package/components/dataGrid/models/exportModel.d.ts +51 -0
  60. package/components/dataGrid/models/gridModel.d.ts +108 -21
  61. package/components/dataGrid/models/groupRowCellModel.d.ts +11 -3
  62. package/components/dataGrid/models/groupRowModel.d.ts +22 -2
  63. package/components/dataGrid/models/rowModel.d.ts +13 -1
  64. package/components/dataGrid/models/sourceGroupRowModel.d.ts +45 -0
  65. package/components/dataGrid/models/sourceLevel.d.ts +71 -0
  66. package/components/dataGrid/models/sourceRowModel.d.ts +29 -0
  67. package/components/dataGrid/models/sourceTreeRowModel.d.ts +23 -0
  68. package/components/dataGrid/models/treeModel.d.ts +94 -0
  69. package/components/dataGrid/models/treeRow.d.ts +22 -0
  70. package/components/dataGrid/models/treeRowModel.d.ts +50 -0
  71. package/components/dataGrid.cjs +1 -1
  72. package/components/dataGrid.d.ts +4 -2
  73. package/components/dataGrid.mjs +4484 -2755
  74. package/components/dialog.cjs +1 -0
  75. package/components/dialog.d.ts +151 -0
  76. package/components/dialog.mjs +223 -0
  77. package/components/dropdown.cjs +1 -1
  78. package/components/dropdown.d.ts +30 -0
  79. package/components/dropdown.mjs +256 -244
  80. package/components/icon.cjs +1 -1
  81. package/components/icon.d.ts +2 -1
  82. package/components/icon.mjs +3 -3
  83. package/components/menu.cjs +1 -0
  84. package/components/menu.d.ts +234 -0
  85. package/components/menu.mjs +422 -0
  86. package/components/overlay.cjs +1 -1
  87. package/components/overlay.d.ts +30 -26
  88. package/components/overlay.mjs +45 -75
  89. package/components/popover.cjs +1 -0
  90. package/components/popover.d.ts +100 -0
  91. package/components/popover.mjs +69 -0
  92. package/components/presence.d.ts +6 -0
  93. package/components/progress.cjs +1 -0
  94. package/components/progress.d.ts +47 -0
  95. package/components/progress.mjs +28 -0
  96. package/components/radioButton.cjs +1 -1
  97. package/components/radioButton.d.ts +8 -0
  98. package/components/radioButton.mjs +1 -1
  99. package/components/radioGroup.cjs +1 -1
  100. package/components/radioGroup.d.ts +15 -2
  101. package/components/radioGroup.mjs +34 -30
  102. package/components/select.d.ts +9 -0
  103. package/components/semantics.cjs +1 -1
  104. package/components/semantics.d.ts +33 -28
  105. package/components/semantics.mjs +3 -3
  106. package/components/slider.cjs +1 -0
  107. package/components/slider.d.ts +98 -0
  108. package/components/slider.mjs +250 -0
  109. package/components/svg.cjs +1 -1
  110. package/components/svg.d.ts +25 -23
  111. package/components/svg.mjs +3 -3
  112. package/components/switch.cjs +1 -1
  113. package/components/switch.d.ts +9 -0
  114. package/components/switch.mjs +1 -1
  115. package/components/tabs.cjs +1 -0
  116. package/components/tabs.d.ts +87 -0
  117. package/components/tabs.mjs +324 -0
  118. package/components/textarea.cjs +1 -1
  119. package/components/textarea.d.ts +14 -0
  120. package/components/textarea.mjs +1 -1
  121. package/components/textbox.cjs +1 -1
  122. package/components/textbox.d.ts +12 -0
  123. package/components/textbox.mjs +1 -1
  124. package/components/toaster.cjs +1 -0
  125. package/components/toaster.d.ts +106 -0
  126. package/components/toaster.mjs +295 -0
  127. package/components/tooltip.cjs +1 -1
  128. package/components/tooltip.d.ts +39 -4
  129. package/components/tooltip.mjs +56 -54
  130. package/docs/a11y.md +199 -0
  131. package/docs/anchor.md +139 -0
  132. package/docs/components.md +48 -0
  133. package/docs/index.md +11 -0
  134. package/docs/props.md +1777 -0
  135. package/effects.cjs +1 -1
  136. package/effects.mjs +1 -1
  137. package/gridExport.cjs +2 -0
  138. package/gridExport.mjs +244 -0
  139. package/identity.cjs +1 -0
  140. package/identity.mjs +12 -0
  141. package/keyboard.cjs +1 -0
  142. package/keyboard.mjs +30 -0
  143. package/layer.cjs +1 -0
  144. package/layer.mjs +127 -0
  145. package/motion.cjs +1 -1
  146. package/motion.mjs +1 -1
  147. package/package.json +134 -10
  148. package/placement.cjs +1 -0
  149. package/placement.mjs +180 -0
  150. package/platform.cjs +1 -1
  151. package/platform.mjs +18 -5
  152. package/react/anchor/useAnchorPosition.d.ts +79 -0
  153. package/react/dialog/useScrollLock.d.ts +12 -0
  154. package/react/hooks/usePortalContainer.d.ts +6 -1
  155. package/react/hooks/useVirtualization.d.ts +24 -35
  156. package/react/popover/usePopoverLayer.d.ts +87 -0
  157. package/react-shared.cjs +1 -1
  158. package/react-shared.mjs +19 -2
  159. package/rsc.cjs +1 -1
  160. package/rsc.mjs +1 -1
  161. package/utils/accordion/accordionUtils.d.ts +48 -0
  162. package/utils/anchor/anchorUtils.d.ts +79 -0
  163. package/utils/array/lazyList.d.ts +10 -0
  164. package/utils/chart/chartPalette.d.ts +15 -0
  165. package/utils/chart/chartUtils.d.ts +2 -8
  166. package/utils/combobox/comboboxUtils.d.ts +89 -0
  167. package/utils/dom/domUtils.d.ts +6 -0
  168. package/utils/environment/environmentUtils.d.ts +10 -0
  169. package/utils/export/csvUtils.d.ts +23 -0
  170. package/utils/export/downloadUtils.d.ts +12 -0
  171. package/utils/export/xlsxUtils.d.ts +56 -0
  172. package/utils/export/zipUtils.d.ts +26 -0
  173. package/utils/keyboard/typeaheadUtils.d.ts +31 -0
  174. package/utils/menu/menuUtils.d.ts +25 -0
  175. package/utils/slider/sliderUtils.d.ts +67 -0
  176. package/utils/tabs/tabsUtils.d.ts +75 -0
  177. package/utils/toast/toastStore.d.ts +73 -0
  178. package/utils/virtual/virtualUtils.d.ts +47 -0
  179. /package/react/{a11y → identity}/useIdentifier.d.ts +0 -0
@@ -0,0 +1,10 @@
1
+ import { default as XlsxUtils } from '../../../utils/export/xlsxUtils';
2
+ import { DataGridCsvOptions, DataGridXlsxOptions, ExportTable } from '../contracts/dataGridContract';
3
+ /** The grid as a worksheet: a bold header over frozen rows, then the table's own rows and their levels. */
4
+ export declare function sheetOf(table: ExportTable, options?: DataGridXlsxOptions, name?: string): XlsxUtils.Sheet;
5
+ /** The workbook's bytes, for a caller that wants to upload the file rather than save it. */
6
+ export declare function xlsx(table: ExportTable, options?: DataGridXlsxOptions, name?: string): Uint8Array<ArrayBuffer>;
7
+ /** The CSV text. Group rows are written where they sit; a file has no outline to collapse them into. */
8
+ export declare function csv(table: ExportTable, options?: DataGridCsvOptions): string;
9
+ export declare function downloadCsv(table: ExportTable, fileName: string, options?: DataGridCsvOptions): void;
10
+ export declare function downloadXlsx(table: ExportTable, fileName: string, options?: DataGridXlsxOptions): void;
@@ -1,4 +1,5 @@
1
- import { RovingFocusItemProps } from '../../react/a11y/useRovingFocus';
1
+ import { ChangeDetails } from '../../react/a11y/useControllableState';
2
+ import { RovingFocusItemProps, RovingFocusReason } from '../../react/a11y/useRovingFocus';
2
3
  /**
3
4
  * The grid's keyboard coordinates, shared with every cell. Rows are numbered as `aria-rowindex` is —
4
5
  * headers, then the filter row, then the body — and a cell asks for its roving tabindex by that pair, so
@@ -13,6 +14,13 @@ export interface GridNavigation {
13
14
  headerRowCount: number;
14
15
  /** The roving tabindex and the ref for one cell, in the coordinates above. */
15
16
  cellProps: (row: number, column: number) => RovingFocusItemProps;
17
+ /**
18
+ * Move the tab stop to a cell without a keystroke having done it — what Tab out of an editor and into
19
+ * the next editable cell moves. `'programmatic'` rather than `'keyboard'` on purpose: a keyboard move
20
+ * focuses the cell from the navigation's own layout effect, which would take focus off an editor
21
+ * mounting under it.
22
+ */
23
+ setActiveCell: (row: number, column: number, details: ChangeDetails<RovingFocusReason>) => void;
16
24
  }
17
25
  /**
18
26
  * Absent outside a DataGrid, and absent on purpose: `DataGridCell` is rendered by the grid and by
@@ -0,0 +1,34 @@
1
+ import { AggregateScope, AggregateValue } from '../contracts/dataGridContract';
2
+ import { default as ColumnModel } from './columnModel';
3
+ import { default as GridModel } from './gridModel';
4
+ /**
5
+ * One aggregated cell: a column, the rows it covered, and the value that came out. The same model backs a
6
+ * group row's aggregate and the footer's, which is why `AggregateCell` is one renderer rather than two.
7
+ */
8
+ export default class AggregateCellModel<TRow> {
9
+ readonly grid: GridModel<TRow>;
10
+ readonly column: ColumnModel<TRow>;
11
+ readonly rows: TRow[];
12
+ readonly scope: AggregateScope;
13
+ /**
14
+ * A total the grid was handed rather than one it works out. Read when it is *asked for*, not when this
15
+ * model is built: a server's group row arrives after the cell that shows it, and a value baked in at
16
+ * construction stayed empty for the life of the row (measured in Chrome 152).
17
+ */
18
+ private readonly given?;
19
+ constructor(grid: GridModel<TRow>, column: ColumnModel<TRow>, rows: TRow[], scope: AggregateScope,
20
+ /**
21
+ * A total the grid was handed rather than one it works out. Read when it is *asked for*, not when this
22
+ * model is built: a server's group row arrives after the cell that shows it, and a value baked in at
23
+ * construction stayed empty for the life of the row (measured in Chrome 152).
24
+ */
25
+ given?: (() => AggregateValue | undefined) | undefined);
26
+ /** This column's value from every row in scope, in row order — what a custom aggregation is handed. */
27
+ private readonly _values;
28
+ get values(): unknown[];
29
+ private readonly _value;
30
+ get value(): AggregateValue;
31
+ get isExpanded(): boolean;
32
+ get isFirst(): boolean;
33
+ get isLast(): boolean;
34
+ }
@@ -0,0 +1,32 @@
1
+ import { AggregateValue, ColumnAggregate } from '../contracts/dataGridContract';
2
+ import { default as AggregateCellModel } from './aggregateCellModel';
3
+ import { default as ColumnModel } from './columnModel';
4
+ import { default as GridModel } from './gridModel';
5
+ /** Run a column's aggregation over one scope. An unknown name answers nothing rather than throwing. */
6
+ export declare function aggregate<TRow>(fn: ColumnAggregate<TRow>, values: unknown[], rows: TRow[]): AggregateValue;
7
+ /**
8
+ * Aggregation concern: which columns aggregate, and the footer they add up to. The arithmetic is in the
9
+ * built-ins above and the per-cell part is `AggregateCellModel` — this is what the grid answers once.
10
+ */
11
+ export default class AggregationModel<TRow> {
12
+ readonly grid: GridModel<TRow>;
13
+ constructor(grid: GridModel<TRow>);
14
+ /** The visible columns carrying an aggregate, in column order. */
15
+ get columns(): ColumnModel<TRow>[];
16
+ /** Whether anything aggregates at all — what decides a group row shows values instead of one wide label. */
17
+ get hasAggregates(): boolean;
18
+ /** Whether the footer row is rendered: asked for, and with something to put in it. */
19
+ get hasFooter(): boolean;
20
+ /** What the footer's leading cell says. `footer: { label }` replaces it; an empty label drops it. */
21
+ get footerLabel(): React.ReactNode;
22
+ /**
23
+ * Which column the label goes in: the first one that holds data and has no aggregate of its own. A number
24
+ * wins its cell, and the row-number, selection and expander columns are too narrow to read a word in.
25
+ */
26
+ get footerLabelColumn(): ColumnModel<TRow> | undefined;
27
+ /**
28
+ * One cell per visible column, over every row the filters left — which is the page rather than the table
29
+ * when the server is paginating, since those are the only rows the grid has.
30
+ */
31
+ readonly footerCells: import('../../../utils/memo').Memo<AggregateCellModel<TRow>[]>;
32
+ }
@@ -0,0 +1,11 @@
1
+ import { Key } from '../contracts/dataGridContract';
2
+ /**
3
+ * The four columns the grid adds for itself, by the key each is found under. Their own module rather
4
+ * than `gridModel`'s, because a model that needs one of them would otherwise import the grid at load
5
+ * time — and `SourceGroupRowModel` extends `GroupRowModel` across exactly that cycle, which leaves the
6
+ * base class undefined depending on which file the bundler reached first.
7
+ */
8
+ export declare const ROW_NUMBER_CELL_KEY: Key;
9
+ export declare const ROW_SELECTION_CELL_KEY: Key;
10
+ export declare const GROUPING_CELL_KEY: Key;
11
+ export declare const ROW_DETAIL_CELL_KEY: Key;
@@ -1,3 +1,4 @@
1
+ import { CellEditorConfig } from '../contracts/dataGridContract';
1
2
  import { default as ColumnModel } from './columnModel';
2
3
  import { default as GridModel } from './gridModel';
3
4
  import { default as RowModel } from './rowModel';
@@ -13,6 +14,31 @@ export default class CellModel<TRow> {
13
14
  get isLast(): boolean;
14
15
  /** Toggle this row's detail panel (used by the row-detail expand cell). */
15
16
  toggleDetail: () => void;
16
- /** Toggle this row's selection (used by the row-selection checkbox cell). */
17
+ /** Whether the row is half-selected — a tree row whose subtree is partly ticked. */
18
+ get indeterminate(): boolean;
19
+ /** Toggle this row's selection (used by the row-selection checkbox cell). The row owns what that means. */
17
20
  toggleSelection: () => void;
21
+ /** Whether this cell can be edited at all — the column's answer about this row. */
22
+ get editable(): boolean;
23
+ /** Whether the editor is open on this cell. One cell at a time, grid-wide. */
24
+ get editing(): boolean;
25
+ /** Which editor this cell opens, resolved from the column or read off the value in it. */
26
+ get editor(): CellEditorConfig<TRow>;
27
+ /** What is in the open editor — the value a custom `EditCell` binds its control to. */
28
+ get draft(): unknown;
29
+ /** What the last commit was rejected with. The editor stays open until it is fixed or abandoned. */
30
+ get error(): string | undefined;
31
+ /** Whether an async `def.onCellEdit` has been asked about this cell and has not answered. */
32
+ get pending(): boolean;
33
+ /**
34
+ * Open the editor on this cell. `initial` is what a printable key pressed on the cell starts it with,
35
+ * replacing the value rather than being appended to it.
36
+ */
37
+ beginEdit: (initial?: string) => void;
38
+ /** Write a new draft into the open editor. */
39
+ setDraft: (value: unknown) => void;
40
+ /** Accept the draft, if `def.onCellEdit` lets it — what Enter does. */
41
+ commitEdit: () => void;
42
+ /** Close the editor with nothing written — what Escape does. */
43
+ cancelEdit: () => void;
18
44
  }
@@ -1,4 +1,4 @@
1
- import { ColumnFilterConfig, ColumnType, ContextMenuConfig, FilterValue, Key, NumberFilterValue, PinPosition, PinPositionInput, SortDirection } from '../contracts/dataGridContract';
1
+ import { ColumnAggregate, ColumnEditable, ColumnFilterConfig, ColumnType, ContextMenuConfig, FilterValue, Key, NumberFilterValue, PinPosition, PinPositionInput, SortDirection } from '../contracts/dataGridContract';
2
2
  import { default as GridModel } from './gridModel';
3
3
  import { default as HeaderCellModel } from './headerCellModel';
4
4
  /** Discriminates the structural role of a column — replaces scattered `key === *_CELL_KEY` checks. */
@@ -52,7 +52,7 @@ export default class ColumnModel<TRow> {
52
52
  get isLastLeaf(): boolean;
53
53
  get key(): Key;
54
54
  get header(): string | undefined;
55
- get align(): "left" | "right" | "center" | "end" | "start" | undefined;
55
+ get align(): "center" | "left" | "right" | "start" | "end" | undefined;
56
56
  /** End-aligned either way it is spelled — `right` is the physical name of `end` in a left-to-right grid. */
57
57
  get isEndAligned(): boolean;
58
58
  /** Whether an explicit `align` was provided (mirrors the original `'align' in def` check). */
@@ -61,6 +61,11 @@ export default class ColumnModel<TRow> {
61
61
  get Cell(): import('react').ComponentType<{
62
62
  cell: import('./cellModel').default<TRow>;
63
63
  }> | undefined;
64
+ /** This column's aggregation, if it has one — the thing that decides it appears on a group row at all. */
65
+ get aggregate(): ColumnAggregate<TRow> | undefined;
66
+ get AggregateCell(): import('react').ComponentType<{
67
+ cell: import('./aggregateCellModel').default<TRow>;
68
+ }> | undefined;
64
69
  get filterable(): boolean | ColumnFilterConfig | undefined;
65
70
  /** Resolved filter config, or undefined when this column isn't filterable. */
66
71
  get filterConfig(): ColumnFilterConfig | undefined;
@@ -75,6 +80,11 @@ export default class ColumnModel<TRow> {
75
80
  setNumberFilter(operator: NumberFilterValue['operator'], value: string | number, valueTo?: string | number): void;
76
81
  setMultiselectFilter(values: (string | number | boolean | null)[]): void;
77
82
  clearFilter(): void;
83
+ /**
84
+ * Whether this column can be edited: the column's own answer, or the grid-wide default it falls back
85
+ * to. A predicate is passed through as it stands — `EditModel` is what asks it about a row.
86
+ */
87
+ get editable(): ColumnEditable<TRow>;
78
88
  /** Whether sorting is enabled for this column. Column-level setting takes priority over grid-level. */
79
89
  get sortable(): boolean;
80
90
  /** Whether resizing is enabled for this column. Column-level setting takes priority over grid-level. */
@@ -0,0 +1,177 @@
1
+ import { DataSource, Key } from '../contracts/dataGridContract';
2
+ import { default as DetailRowModel } from './detailRowModel';
3
+ import { default as GridModel } from './gridModel';
4
+ import { default as GroupRowModel } from './groupRowModel';
5
+ import { default as RowModel } from './rowModel';
6
+ import { BlockStatus } from './sourceLevel';
7
+ export type { BlockStatus };
8
+ /**
9
+ * The server row model: the grid asks `def.dataSource` for blocks and this holds them. Everything the
10
+ * grid would have done over `data` — filtering, sorting, paging, grouping — is a *request* here, so the
11
+ * browser never holds more than the blocks in play.
12
+ *
13
+ * Two invariants are worth naming. A response is only accepted while the query it was asked under is
14
+ * still the current one: `_query` is bumped by every sort, filter and grouping change, a request carries
15
+ * the value it was made at, and a late answer to an old question is dropped rather than written over a
16
+ * new one — which is the whole of the out-of-order problem an async row model has. And the cache is a
17
+ * *tree* of levels, one per open group: the rows the grid draws are a walk over it, so a group holds its
18
+ * children only while somebody has it open.
19
+ */
20
+ export default class DataSourceModel<TRow> {
21
+ readonly grid: GridModel<TRow>;
22
+ constructor(grid: GridModel<TRow>);
23
+ /** The top level, and every open group's beside it — one entry per path somebody has opened. */
24
+ private root;
25
+ private levels;
26
+ /** Blocks in the order they were last wanted, level and index; the front of it is what eviction takes. */
27
+ private recent;
28
+ private _query;
29
+ get config(): DataSource<TRow> | undefined;
30
+ /** Whether the grid fetches its own rows. With no datasource every getter here is inert. */
31
+ get enabled(): boolean;
32
+ /** Whether the server answers a group level, which is what puts *Group by* back in the column menu. */
33
+ get canGroup(): boolean;
34
+ /**
35
+ * Whether the levels are a tree's rather than a grouping's. The two are one mechanism — a path, a level
36
+ * per open path, the same eviction — and they are mutually exclusive because a level cannot be both:
37
+ * a tree's own rows are the grouping its data already has.
38
+ */
39
+ get isTree(): boolean;
40
+ /**
41
+ * The columns the server is grouping by, outermost first. A level at depth `d` holds groups of
42
+ * `groupBy[d]`; a level as deep as this is long holds leaf rows.
43
+ */
44
+ get groupBy(): Key[];
45
+ get blockSize(): number;
46
+ private get maxBlocks();
47
+ /**
48
+ * Bumped by every change that makes the cache stale. The adapter's fetch effect depends on it, so an
49
+ * invalidation that leaves the visible range where it was still refills — which every filter does.
50
+ */
51
+ get queryVersion(): number;
52
+ /** The count the server gave for the top level, once it has given one. */
53
+ get totalCount(): number | undefined;
54
+ /** Whether any block of any level is in flight — what the loading bar is drawn from. */
55
+ get isLoading(): boolean;
56
+ /** The most recent failure still unanswered, which is what the error strip reports. */
57
+ get error(): unknown;
58
+ private _segments?;
59
+ private _byLevel?;
60
+ /**
61
+ * The rows the grid draws, as runs of one level each: the top level's rows, with every open group's own
62
+ * level spliced in directly after the group row that opened it. Rebuilt whenever a block lands or a
63
+ * group is toggled, and it is also where a level is created and where a closed one is disposed of —
64
+ * a level nothing reaches is a level whose group has been shut or whose group row has been dropped.
65
+ */
66
+ private segments;
67
+ /** The same runs grouped by the level they came from — how a level's own index becomes a display one. */
68
+ private byLevel;
69
+ /** Which rows of a level are open — groups or tree rows — ascending, with the level each one holds. */
70
+ private expansionsOf;
71
+ /**
72
+ * The same for a tree, where every level's rows are data rows and any of them may hold more. A row is
73
+ * open when it says it has children and the tree model has it open — walked over the blocks in hand,
74
+ * because a row nobody has fetched is a row nobody could have pressed the chevron of.
75
+ */
76
+ private treeExpansionsOf;
77
+ /**
78
+ * Every tree row that is open *and* reachable, which is what `onExpandedTreeKeysChange` reports. The
79
+ * levels are exactly that list: one per open path, and the walk disposes of any the rows no longer
80
+ * reach — so a row under a shut one is not open however it is marked.
81
+ */
82
+ openTreeKeys(): Key[];
83
+ private levelFor;
84
+ /** The run a display index falls in, in O(log n) over the runs rather than over the rows. */
85
+ private segmentAt;
86
+ /**
87
+ * How many rows the grid lays out: the walk's own length, which is the top level plus everything open
88
+ * inside it. With no grouping it is exactly the top level's count, which is all stage 1 ever had.
89
+ */
90
+ get rowCount(): number;
91
+ /** One model per row, by level and then by index, built when somebody looks at that row. */
92
+ private models;
93
+ /** How long the last row list was, which is the only thing that can make it stale. */
94
+ private listLength;
95
+ /**
96
+ * The grid's rows. Lazy, because this is the list a million-row grid lays out: a model per row cost
97
+ * 1.4 seconds of blocked main thread on every block that arrived (measured, Chrome 152), and the rows
98
+ * read their values through the cache anyway, so there was never anything to rebuild.
99
+ */
100
+ rowList(): (RowModel<TRow> | GroupRowModel<TRow>)[];
101
+ /**
102
+ * The same rows with each open detail panel after the row that opened it. Only a row that has arrived
103
+ * can be expanded, so the positions are found by walking the blocks in hand rather than the result set.
104
+ */
105
+ flatRowList<TItem>(rows: TItem[]): (TItem | DetailRowModel<TRow>)[];
106
+ /**
107
+ * Where the rows sit once the open detail panels are counted in, and how tall the lot is. Lazy for the
108
+ * same reason the row list is — the binary search the viewport runs over it reads a handful of entries.
109
+ */
110
+ rowOffsets(flat: (RowModel<TRow> | GroupRowModel<TRow> | DetailRowModel<TRow>)[]): {
111
+ offsets: number[];
112
+ totalHeight: number;
113
+ };
114
+ /**
115
+ * Where each open detail panel sits in the flat list, ascending. The i-th one follows its own row and
116
+ * the i panels already inserted above it, which is what makes the mapping back an O(log n) search.
117
+ *
118
+ * Only a row that has arrived can be expanded, so this walks the blocks in hand — a few thousand rows
119
+ * at the most — rather than the result set, which is the whole million.
120
+ */
121
+ private detailPositions;
122
+ /**
123
+ * Every row in hand, in the order they are drawn. Read off the blocks rather than the row list, which
124
+ * is lazy — and it is the blocks that are the honest answer anyway: a select-all cannot reach rows
125
+ * nobody has fetched, and with a group shut its rows were never fetched at all.
126
+ */
127
+ loadedRows(): TRow[];
128
+ /** Every data row the cache holds, with where it is drawn — the blocks in hand, never the result set. */
129
+ private eachLoadedLeafRow;
130
+ /** The model for one row of the display list, kept so React sees the same object between renders. */
131
+ private rowModelAt;
132
+ /** The column a level groups by. It stays in `leafs` while it is grouped, only hidden from the body. */
133
+ private groupColumnAt;
134
+ /** How many rows the grid lays out right now: the page's worth, or the whole list. */
135
+ private visibleLength;
136
+ /** Which absolute rows are on screen's worth of the display list — a page, or everything. */
137
+ private visibleRange;
138
+ rowAt(index: number): TRow | undefined;
139
+ statusAt(index: number): BlockStatus | 'missing';
140
+ /**
141
+ * Ask for everything covering `[startIndex, endIndex)` of the display list. Called from an effect with
142
+ * the viewport's own window; when the grid is paginated the page is the range, so the pager and the
143
+ * scroller are one path. A range crossing an open group asks its level for a block of its own.
144
+ */
145
+ request(startIndex: number, endIndex: number): void;
146
+ /**
147
+ * A group opened or closed. The walk over the levels is a different walk now — and this is the only
148
+ * change that reaches it without a block having moved, so nothing else would drop the cached one.
149
+ */
150
+ expansionChanged(): void;
151
+ /** Fetch every block that failed, which is what the error strip's Retry does. */
152
+ retry: () => void;
153
+ /**
154
+ * The query changed underneath the cache: every block is about a question nobody is asking any more.
155
+ * Requests in flight are aborted, and the next `request` refills from wherever the viewport now is —
156
+ * which the adapter has put back at the top, since a new query has no scroll position to preserve.
157
+ *
158
+ * The count is deliberately *kept*: the next response replaces it, and dropping it in between collapses
159
+ * the scrollbar to one block and the pager to one page on every keystroke in a filter box.
160
+ */
161
+ invalidate(): void;
162
+ /** Mark a block as wanted now, so eviction takes the ones the viewport left behind. */
163
+ private touch;
164
+ private bump;
165
+ /** Drop the least recently wanted blocks, and abort any of them still in flight. */
166
+ private evict;
167
+ /**
168
+ * Rows moved, so React has to hear about it. The row list itself is rebuilt only when its *length*
169
+ * changes: the models read their values through this cache, so a block arriving changes what fifty
170
+ * rows show without one of them being replaced — which is what keeps a selection and a focused cell
171
+ * where they were. The flat list is another matter, since a row that has only just arrived may be one
172
+ * whose detail panel is open, or one whose group somebody left expanded.
173
+ */
174
+ changed(): void;
175
+ }
176
+ /** How many of an ascending list of positions fall below `value` — a lower bound, in O(log n). */
177
+ export declare function countBelow(positions: number[], value: number): number;
@@ -0,0 +1,77 @@
1
+ import { CellEdit, CellEditorConfig, Key } from '../contracts/dataGridContract';
2
+ import { default as ColumnModel } from './columnModel';
3
+ import { default as GridModel } from './gridModel';
4
+ import { default as RowModel } from './rowModel';
5
+ /** What a rejection with no message of its own says. A silent refusal is one nobody can act on. */
6
+ export declare const DEFAULT_EDIT_ERROR = "Invalid value";
7
+ /** A key that starts an edit by replacing the value: one printable character, unmodified. */
8
+ export declare function isTypingKey(event: React.KeyboardEvent): boolean;
9
+ /**
10
+ * Cell editing: which cell is open, what is in it, what a commit is judged by, and the values the grid
11
+ * has accepted. All of it lives here rather than in the editor component, so the four built-in editors
12
+ * and one of your own are the same three calls — read `draft`, `setDraft`, `commit` or `cancel`.
13
+ *
14
+ * The accepted values are an **overlay** on the rows the grid was given: it does not own `data`, and a
15
+ * grid over a `def.dataSource` owns even less of it, so a value that was only reported would be gone
16
+ * again on the next render. It is read where a value is *displayed* — cells and exports — and nowhere a
17
+ * value is *compared*, so an edit never re-sorts or re-filters the grid under the person making it.
18
+ */
19
+ export default class EditModel<TRow> {
20
+ readonly grid: GridModel<TRow>;
21
+ constructor(grid: GridModel<TRow>);
22
+ /** The accepted values, keyed by cell. Cleared by `clearEdits()` and by a datasource refresh. */
23
+ private readonly values;
24
+ private _edits;
25
+ private _active?;
26
+ private _token;
27
+ /** Whether any column can be edited — what decides the grid reads a keystroke as a way in. */
28
+ get enabled(): boolean;
29
+ /** Whether this row and column can be edited. A row nobody has fetched yet cannot. */
30
+ isEditable(row: RowModel<TRow>, column: ColumnModel<TRow>): boolean;
31
+ /** The editor a cell opens, worked out from the value in it when the column names none. */
32
+ editorFor(column: ColumnModel<TRow>, value: unknown): CellEditorConfig<TRow>;
33
+ isEditing(rowKey: Key, columnKey: Key): boolean;
34
+ /** What is in the open editor. `undefined` when none is open, which a cell checks with `isEditing`. */
35
+ get draft(): unknown;
36
+ /** What the last commit was rejected with. The editor stays open on it. */
37
+ get error(): string | undefined;
38
+ /** Whether an async validator has been asked and has not answered. */
39
+ get pending(): boolean;
40
+ /**
41
+ * Open an editor. `initial` is what a printable key typed on the cell starts it with — the value it
42
+ * replaces rather than one it is appended to, which is how every spreadsheet reads a keystroke. Only
43
+ * the two editors that are *typed into* take it; see `seedFor`.
44
+ */
45
+ begin(row: RowModel<TRow>, column: ColumnModel<TRow>, value: unknown, initial?: string): void;
46
+ /** Open the editor on a cell named by grid coordinates, which is where Tab lands. */
47
+ beginAt(row: number, column: number, initial?: string): boolean;
48
+ setDraft(value: unknown): void;
49
+ /** Close the editor with nothing written. Also what an accepted commit does on its way out. */
50
+ cancel(): void;
51
+ /**
52
+ * Accept the draft, if `def.onCellEdit` lets it. A value that did not change is not an edit at all and
53
+ * closes the editor without asking, which is what makes Tab through a row of cells cost nothing.
54
+ */
55
+ commit(): void;
56
+ /** What an answer — a validator's, or its own for a synchronous edit — does to the open editor. */
57
+ private settle;
58
+ /** What a cell shows: the accepted value when there is one, the row's own otherwise. */
59
+ valueOf(rowKey: Key, columnKey: Key, raw: unknown): unknown;
60
+ /** Every edit the grid has accepted, oldest first. */
61
+ get edits(): CellEdit<TRow>[];
62
+ /**
63
+ * Give the edits back to the host: the values stop being the grid's and the rows answer for themselves
64
+ * again. A datasource refresh does the same on its own — the blocks are being fetched afresh, so what
65
+ * the server says next is the newer answer.
66
+ */
67
+ clearEdits: () => void;
68
+ /**
69
+ * The next editable cell, as a pair of grid coordinates — along the row first and on into the rows
70
+ * after it, which is the order Tab walks a spreadsheet in. Nothing when there is none: Tab then does
71
+ * what Tab does in a grid, and leaves.
72
+ */
73
+ nextEditable(row: number, column: number, back?: boolean): {
74
+ row: number;
75
+ column: number;
76
+ } | undefined;
77
+ }
@@ -0,0 +1,51 @@
1
+ import { DataGridExportOptions, ExportTable, Key } from '../contracts/dataGridContract';
2
+ import { default as ColumnModel } from './columnModel';
3
+ import { default as GridModel } from './gridModel';
4
+ /**
5
+ * What an export writes, decided here and rendered by nobody: the columns, the rows the filters and the
6
+ * sort left, and the grouping as levels rather than as indentation. Both formats are handed this same
7
+ * table, which is why a CSV and a workbook of the same grid hold the same figures.
8
+ *
9
+ * It is a model rather than part of the writers so that it can be tested without producing a file, and so
10
+ * the writers stay in the lazy chunk — this is the only export code the grid's own bundle carries.
11
+ */
12
+ export default class ExportModel<TRow> {
13
+ readonly grid: GridModel<TRow>;
14
+ constructor(grid: GridModel<TRow>);
15
+ /**
16
+ * The columns a file gets: the visible data columns, **plus** the ones grouping took off the screen.
17
+ * A grouped column is not hidden — its values moved to the group rows — and a spreadsheet with no
18
+ * Country column in it is not the grid that was exported.
19
+ */
20
+ columns(keys?: Key[]): ColumnModel<TRow>[];
21
+ /** A column's heading, which is its own `header` or the key it reads. */
22
+ header(column: ColumnModel<TRow>): string;
23
+ /** Its width in characters — the unit a spreadsheet sizes columns in, from the pixels the grid uses. */
24
+ width(column: ColumnModel<TRow>): number;
25
+ /**
26
+ * One row's value for one column: the column's own `exportValue` when it has one, else the raw field —
27
+ * either way through the edits, so a file carries what the grid is showing rather than what it was given.
28
+ */
29
+ private value;
30
+ /** A column's aggregate over a set of rows, or null where it has no aggregation. */
31
+ private aggregateOf;
32
+ /**
33
+ * The table. Group rows carry their own value in the column they group by and a total in every column
34
+ * that aggregates; a collapsed group exports collapsed, so the file opens looking like the screen.
35
+ */
36
+ table(options?: DataGridExportOptions): ExportTable;
37
+ /**
38
+ * A tree, as Excel's outline: a row's level is its depth and a shut row exports `collapsed`, with
39
+ * everything under it `hidden` — the same two flags a collapsed group writes, so the file opens
40
+ * looking like the screen. The rows are walked rather than the models: a shut row builds none of its
41
+ * children, and an export writes the whole tree.
42
+ */
43
+ private walkTree;
44
+ /**
45
+ * The grand totals, over the rows the filters left. The label goes in the leading column with nothing
46
+ * of its own to say — the same column it occupies on screen when that column is exported at all.
47
+ */
48
+ private footerRow;
49
+ /** The file's name, without an extension: what was asked for, else the grid's title, else `export`. */
50
+ fileName(options?: DataGridExportOptions): string;
51
+ }