@box-kite/react 2.2.4 → 2.2.6

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 (167) hide show
  1. package/.claude/rules/box-kite-rules.md +11 -1
  2. package/.claude/skills/box-kite/SKILL.md +11 -1
  3. package/.claude/skills/box-kite/references/components.md +83 -3
  4. package/.cursor/rules/box-kite.mdc +11 -1
  5. package/AGENTS.md +11 -1
  6. package/BOX_AI_CONTEXT.md +371 -25
  7. package/BOX_KITE_AI_CONTEXT.md +371 -25
  8. package/behavior.cjs +1 -1
  9. package/behavior.mjs +57 -57
  10. package/box.cjs +1 -1
  11. package/box.d.ts +5 -0
  12. package/box.mjs +15 -15
  13. package/catalog.cjs +1 -1
  14. package/catalog.mjs +906 -0
  15. package/client.cjs +1 -1
  16. package/client.mjs +94 -80
  17. package/components/calendar.cjs +1 -0
  18. package/components/calendar.d.ts +77 -0
  19. package/components/calendar.mjs +483 -0
  20. package/components/dashboard.cjs +1 -1
  21. package/components/dashboard.mjs +1 -1
  22. package/components/dataGrid/components/dataGridBooleanValue.d.ts +11 -0
  23. package/components/dataGrid/components/dataGridDateParts.d.ts +40 -0
  24. package/components/dataGrid/components/dataGridDateValue.d.ts +14 -0
  25. package/components/dataGrid/components/dataGridList.d.ts +12 -0
  26. package/components/dataGrid/components/dataGridListAggregate.d.ts +7 -0
  27. package/components/dataGrid/components/dataGridListFilter.d.ts +7 -0
  28. package/components/dataGrid/components/dataGridListFilterSheet.d.ts +11 -0
  29. package/components/dataGrid/components/dataGridListFooter.d.ts +13 -0
  30. package/components/dataGrid/components/dataGridListGroup.d.ts +13 -0
  31. package/components/dataGrid/components/dataGridListItem.d.ts +21 -0
  32. package/components/dataGrid/components/dataGridListLayout.d.ts +20 -0
  33. package/components/dataGrid/components/dataGridListRecord.d.ts +11 -0
  34. package/components/dataGrid/components/dataGridListSelectionBar.d.ts +11 -0
  35. package/components/dataGrid/components/dataGridListSheet.d.ts +30 -0
  36. package/components/dataGrid/components/dataGridListSortSheet.d.ts +10 -0
  37. package/components/dataGrid/components/dataGridListToolbar.d.ts +10 -0
  38. package/components/dataGrid/components/dataGridListValue.d.ts +12 -0
  39. package/components/dataGrid/contracts/dataGridContract.d.ts +70 -11
  40. package/components/dataGrid/models/columnModel.d.ts +3 -1
  41. package/components/dataGrid/models/editModel.d.ts +3 -1
  42. package/components/dataGrid/models/gridModel.d.ts +3 -0
  43. package/components/dataGrid/models/listModel.d.ts +129 -0
  44. package/components/dataGrid/models/localeText.d.ts +36 -0
  45. package/components/dataGrid/models/viewportModel.d.ts +0 -2
  46. package/components/dataGrid/useDateParts.d.ts +17 -0
  47. package/components/dataGrid/useListLayout.d.ts +13 -0
  48. package/components/dataGrid.cjs +3 -3
  49. package/components/dataGrid.mjs +1251 -854
  50. package/components/dateField.cjs +1 -0
  51. package/components/dateField.d.ts +78 -0
  52. package/components/dateField.mjs +313 -0
  53. package/components/datePicker.cjs +1 -0
  54. package/components/datePicker.d.ts +120 -0
  55. package/components/datePicker.mjs +529 -0
  56. package/components/dateTime.cjs +1 -0
  57. package/components/dateTime.d.ts +23 -0
  58. package/components/dateTime.mjs +34 -0
  59. package/components/dialog.cjs +1 -1
  60. package/components/dialog.mjs +29 -29
  61. package/components/list/listItemParts.d.ts +9 -0
  62. package/components/list.cjs +1 -0
  63. package/components/list.d.ts +118 -0
  64. package/components/list.mjs +391 -0
  65. package/components/menu.cjs +1 -1
  66. package/components/menu.mjs +25 -25
  67. package/components/overlay.cjs +1 -1
  68. package/components/overlay.mjs +12 -12
  69. package/components/semantics.d.ts +29 -29
  70. package/components/slider.cjs +1 -1
  71. package/components/slider.mjs +1 -1
  72. package/components/sortableList.cjs +1 -0
  73. package/components/sortableList.d.ts +49 -0
  74. package/components/sortableList.mjs +384 -0
  75. package/components/swipeItem.cjs +1 -0
  76. package/components/swipeItem.d.ts +52 -0
  77. package/components/swipeItem.mjs +321 -0
  78. package/components/tabs.cjs +1 -1
  79. package/components/tabs.mjs +1 -1
  80. package/components/timeZoneSelect.cjs +1 -0
  81. package/components/timeZoneSelect.d.ts +52 -0
  82. package/components/timeZoneSelect.mjs +74 -0
  83. package/components/toaster.cjs +1 -1
  84. package/components/toaster.mjs +24 -24
  85. package/components/virtualList.cjs +1 -0
  86. package/components/virtualList.d.ts +32 -0
  87. package/components/virtualList.mjs +188 -0
  88. package/dataGridDateParts.cjs +1 -0
  89. package/dataGridDateParts.mjs +223 -0
  90. package/dataGridList.cjs +1 -0
  91. package/dataGridList.mjs +1314 -0
  92. package/dataGridListLayout.cjs +1 -0
  93. package/dataGridListLayout.mjs +49 -0
  94. package/date-environment.cjs +1 -0
  95. package/date-environment.mjs +29 -0
  96. package/date-input.cjs +1 -0
  97. package/date-input.mjs +346 -0
  98. package/date-math.cjs +1 -0
  99. package/date-math.mjs +317 -0
  100. package/date.cjs +1 -0
  101. package/date.d.ts +40 -0
  102. package/date.mjs +4 -0
  103. package/dates.cjs +1 -0
  104. package/dates.mjs +689 -0
  105. package/docs/components.md +10 -1
  106. package/icons/closeIcon.d.ts +2 -0
  107. package/icons/filterIcon.d.ts +2 -0
  108. package/layer.cjs +1 -1
  109. package/layer.mjs +1 -1
  110. package/mcp/src/data.d.ts +2 -0
  111. package/package.json +178 -22
  112. package/placement.cjs +1 -1
  113. package/placement.mjs +10 -10
  114. package/platform.cjs +1 -1
  115. package/platform.mjs +4 -1
  116. package/react/a11y/useControllableState.d.ts +2 -1
  117. package/react/boxComponent.d.ts +1 -1
  118. package/react/componentsContext.d.ts +4 -0
  119. package/react/componentsProvider.d.ts +10 -0
  120. package/react/date/dateChange.d.ts +18 -0
  121. package/react/date/dateEnvironment.d.ts +34 -0
  122. package/react/resolveStyles.d.ts +2 -1
  123. package/react/theme/theme.d.ts +6 -1
  124. package/react-shared.cjs +1 -1
  125. package/react-shared.mjs +6 -6
  126. package/registry/blocks/dashboard-shell/dashboard-shell.d.ts +3 -1
  127. package/registry/designs/store/address-form.d.ts +11 -0
  128. package/registry/designs/store/cart-items.d.ts +10 -0
  129. package/registry/designs/store/cart-page.d.ts +4 -0
  130. package/registry/designs/store/checkout-page.d.ts +7 -0
  131. package/registry/designs/store/credit-card-form.d.ts +10 -0
  132. package/registry/designs/store/form-field.d.ts +19 -0
  133. package/registry/designs/store/order-summary.d.ts +18 -0
  134. package/registry/designs/store/product-art.d.ts +26 -0
  135. package/registry/designs/store/product-card.d.ts +11 -0
  136. package/registry/designs/store/product-gallery.d.ts +11 -0
  137. package/registry/designs/store/product-grid.d.ts +10 -0
  138. package/registry/designs/store/product-page.d.ts +5 -0
  139. package/registry/designs/store/quantity-stepper.d.ts +13 -0
  140. package/registry/designs/store/shipping-method.d.ts +14 -0
  141. package/registry/designs/store/store-data.d.ts +53 -0
  142. package/registry/designs/store/store-design.d.ts +63 -0
  143. package/registry/designs/store/store-shell.d.ts +12 -0
  144. package/registry/designs/store/storefront-page.d.ts +4 -0
  145. package/registry/designs/store/variant-picker.d.ts +15 -0
  146. package/rsc.cjs +1 -1
  147. package/rsc.d.ts +2 -0
  148. package/rsc.mjs +1 -1
  149. package/scrolling.cjs +1 -0
  150. package/scrolling.mjs +22 -0
  151. package/utils/date/calendar.d.ts +44 -0
  152. package/utils/date/calendarModel.d.ts +46 -0
  153. package/utils/date/dateTime.d.ts +144 -0
  154. package/utils/date/fieldModel.d.ts +74 -0
  155. package/utils/date/format.d.ts +39 -0
  156. package/utils/date/iso.d.ts +40 -0
  157. package/utils/date/locale.d.ts +17 -0
  158. package/utils/date/parse.d.ts +20 -0
  159. package/utils/date/settings.d.ts +26 -0
  160. package/utils/date/value.d.ts +43 -0
  161. package/utils/date/zoneOptions.d.ts +19 -0
  162. package/utils/date/zones.d.ts +32 -0
  163. package/utils/scroll/scrollUtils.d.ts +6 -0
  164. package/utils/sortable/sortableUtils.d.ts +25 -0
  165. package/utils/swipe/swipeUtils.d.ts +53 -0
  166. package/utils/virtual/measuredWindow.d.ts +28 -0
  167. package/utils/virtual/rowSearch.d.ts +11 -0
@@ -0,0 +1,13 @@
1
+ import { default as GroupRowModel } from '../models/groupRowModel';
2
+ interface Props<TRow> {
3
+ row: GroupRowModel<TRow>;
4
+ /** The row's version (`GridModel.rowVersion`). Not read: it is what tells the memo the row moved. */
5
+ version: string;
6
+ }
7
+ /**
8
+ * A group as a section header: the value, how many rows it holds, and their totals underneath. The toggle is
9
+ * the item's `List.Action`, so the whole header opens and closes the group.
10
+ */
11
+ declare function DataGridListGroupImpl<TRow>(props: Props<TRow>): import("react").JSX.Element;
12
+ declare const DataGridListGroup: typeof DataGridListGroupImpl;
13
+ export default DataGridListGroup;
@@ -0,0 +1,21 @@
1
+ import { default as RowModel } from '../models/rowModel';
2
+ interface Props<TRow> {
3
+ row: RowModel<TRow>;
4
+ /** Where the row sits in the grid's rows — what the record view opens at. */
5
+ index: number;
6
+ /** `aria-posinset`/`aria-setsize`: where the item is in the whole list, not in the part drawn. */
7
+ position?: number;
8
+ setSize?: number;
9
+ /** The row's version (`GridModel.rowVersion`). Not read: it is what tells the memo the row moved. */
10
+ version: string;
11
+ }
12
+ /**
13
+ * One row as a `List.Item`: a kicker, the title with one value opposite it, a subtitle, and a few labelled
14
+ * fields — the slots `ListModel.layout` hands out. The title is the item's `List.Action`: it opens the record
15
+ * view, and while the list is selecting it is the label of the row's checkbox, so a press anywhere on the
16
+ * item ticks it.
17
+ */
18
+ declare function DataGridListItemImpl<TRow>(props: Props<TRow>): import("react").JSX.Element;
19
+ /** Memoized on its props, so one row's selection or expansion redraws that item and not the list. */
20
+ declare const DataGridListItem: typeof DataGridListItemImpl;
21
+ export default DataGridListItem;
@@ -0,0 +1,20 @@
1
+ import { BoxStyles } from '../../../types';
2
+ /**
3
+ * The list layout's geometry, shared between its parts. The paint — colours, borders, states — is the
4
+ * `datagrid.list` style tree, which every engine entry carries; this is only ever in the DataGrid's chunk.
5
+ */
6
+ declare namespace DataGridListLayout {
7
+ /** A square control a thumb can hit: 44px, the Apple and WCAG target. */
8
+ const ICON_BUTTON: BoxStyles;
9
+ /** A pill in the toolbar: Sort, Filters, Select. */
10
+ const PILL: BoxStyles;
11
+ /** One line of text that ends in an ellipsis rather than a second line. */
12
+ const TRUNCATE: BoxStyles;
13
+ /** A full-width field in a sheet: 44px tall, and 16px type so a phone does not zoom in on focus. */
14
+ const INPUT: BoxStyles;
15
+ /** A labelled value: the label small and muted over the value. */
16
+ const LABEL: BoxStyles;
17
+ /** The sheet's big buttons, at the bottom where a thumb is. */
18
+ const SHEET_BUTTON: BoxStyles;
19
+ }
20
+ export default DataGridListLayout;
@@ -0,0 +1,11 @@
1
+ import { default as GridModel } from '../models/gridModel';
2
+ interface Props<TRow> {
3
+ grid: GridModel<TRow>;
4
+ }
5
+ /**
6
+ * One row at a time: every column of it, a label over each value, in a sheet with a pager — the drill-in a
7
+ * list item leads to. The pager follows the list's own order and filters, Left/Right and a sideways swipe
8
+ * step it, and an editable column is edited here, through the same `def.onCellEdit` a table cell goes through.
9
+ */
10
+ export default function DataGridListRecord<TRow>(props: Props<TRow>): import("react").JSX.Element;
11
+ export {};
@@ -0,0 +1,11 @@
1
+ import { default as GridModel } from '../models/gridModel';
2
+ interface Props<TRow> {
3
+ grid: GridModel<TRow>;
4
+ }
5
+ /**
6
+ * The selection, pinned to the bottom of the screen while there is one: how many rows are ticked and the two
7
+ * ways to change that in bulk. At the bottom because that is where a thumb is, and where a phone's own
8
+ * contextual bars put what a selection is for.
9
+ */
10
+ export default function DataGridListSelectionBar<TRow>(props: Props<TRow>): import("react").JSX.Element | null;
11
+ export {};
@@ -0,0 +1,30 @@
1
+ import { DialogTrigger } from '../../dialog';
2
+ import { default as GridModel } from '../models/gridModel';
3
+ interface Props<TRow> {
4
+ grid: GridModel<TRow>;
5
+ open: boolean;
6
+ /** The trigger was pressed. */
7
+ onOpen?: () => void;
8
+ onClose: () => void;
9
+ title: React.ReactNode;
10
+ /** The button that opens it, so focus goes back there when it closes. */
11
+ trigger?: (trigger: DialogTrigger) => React.ReactNode;
12
+ /** Controls in the header between the title and the close button — the record view's pager. */
13
+ actions?: React.ReactNode;
14
+ footer?: React.ReactNode;
15
+ /** The record view: as tall as a long row needs. */
16
+ tall?: boolean;
17
+ /** Handlers for the scrolling body — the record view's swipe. */
18
+ bodyProps?: React.HTMLAttributes<HTMLDivElement>;
19
+ bodyRef?: React.Ref<HTMLDivElement>;
20
+ /** Keys anywhere in the sheet — the record view's pager. */
21
+ onKeyDown?: (event: React.KeyboardEvent) => void;
22
+ children: React.ReactNode;
23
+ }
24
+ /**
25
+ * A bottom sheet: a modal `<dialog>` docked to the bottom edge, which brings the top layer, the backdrop,
26
+ * Escape, focus containment and focus return with it. The header is a handle — pulled down far enough, the
27
+ * sheet closes, the way a sheet on a phone does.
28
+ */
29
+ export default function DataGridListSheet<TRow>(props: Props<TRow>): import("react").JSX.Element;
30
+ export {};
@@ -0,0 +1,10 @@
1
+ import { default as GridModel } from '../models/gridModel';
2
+ interface Props<TRow> {
3
+ grid: GridModel<TRow>;
4
+ }
5
+ /**
6
+ * The Sort button and the sheet it opens. A list has no headers to press, so the sort is a choice of column
7
+ * and a choice of direction — two radio groups, applied as they are picked, since a sort is one decision.
8
+ */
9
+ export default function DataGridListSortSheet<TRow>(props: Props<TRow>): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ import { default as GridModel } from '../models/gridModel';
2
+ interface Props<TRow> {
3
+ grid: GridModel<TRow>;
4
+ }
5
+ /**
6
+ * The list's toolbar: the title and how many rows there are, the search, and a row of pills — Sort, Filters,
7
+ * Select — followed by one chip per filter in force, each removable on its own.
8
+ */
9
+ export default function DataGridListToolbar<TRow>(props: Props<TRow>): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,12 @@
1
+ import { default as ColumnModel } from '../models/columnModel';
2
+ import { default as RowModel } from '../models/rowModel';
3
+ interface Props<TRow> {
4
+ row: RowModel<TRow>;
5
+ column: ColumnModel<TRow>;
6
+ }
7
+ /**
8
+ * One value of a row, drawn the way its column draws it in the table: through the column's own `Cell` where
9
+ * there is one — a badge, a sparkline, a link — so a list item and a table row never disagree.
10
+ */
11
+ export default function DataGridListValue<TRow>(props: Props<TRow>): import("react").JSX.Element | null;
12
+ export {};
@@ -2,6 +2,8 @@ import { BoxProps } from '../../../box';
2
2
  import { ChangeHandler } from '../../../react/a11y/useControllableState';
3
3
  import { ComponentsAndVariants } from '../../../types';
4
4
  import { SortDirection } from '../../../utils/array/arrayUtils';
5
+ import { FormatOptions } from '../../../utils/date/format';
6
+ import { ZoneInput } from '../../../utils/date/zones';
5
7
  import { default as AggregateCellModel } from '../models/aggregateCellModel';
6
8
  import { default as CellModel } from '../models/cellModel';
7
9
  import { DataGridLocaleText } from '../models/localeText';
@@ -163,7 +165,7 @@ export interface DataGridPagination {
163
165
  pageSize: number;
164
166
  }
165
167
  /** Filter type for column-level filtering */
166
- export type ColumnFilterType = 'text' | 'number' | 'multiselect';
168
+ export type ColumnFilterType = 'text' | 'number' | 'multiselect' | 'date';
167
169
  /** Text filter configuration (fuzzy search) */
168
170
  export interface TextFilterValue {
169
171
  type: 'text';
@@ -181,8 +183,19 @@ export interface MultiselectFilterValue {
181
183
  type: 'multiselect';
182
184
  values: (string | number | boolean | null)[];
183
185
  }
186
+ /**
187
+ * Date filter: one day, before or after one, or a span of days, each `YYYY-MM-DD` — compared on the reader's
188
+ * calendar, so an instant late on the 19th in their zone is on the 19th whatever UTC says.
189
+ */
190
+ export interface DateFilterValue {
191
+ type: 'date';
192
+ operator: 'on' | 'before' | 'after' | 'between';
193
+ value: string;
194
+ /** For 'between': the last day, included. */
195
+ valueTo?: string;
196
+ }
184
197
  /** Union type for all filter values */
185
- export type FilterValue = TextFilterValue | NumberFilterValue | MultiselectFilterValue;
198
+ export type FilterValue = TextFilterValue | NumberFilterValue | MultiselectFilterValue | DateFilterValue;
186
199
  /** Column filters record - maps column key to filter value */
187
200
  export type ColumnFilters<TRow> = Partial<Record<keyof TRow | Key, FilterValue>>;
188
201
  /** Filter configuration for a column */
@@ -197,10 +210,10 @@ export interface ColumnFilterConfig {
197
210
  }[];
198
211
  /** For number: step value for input */
199
212
  step?: number;
200
- /** For number: min value */
201
- min?: number;
202
- /** For number: max value */
203
- max?: number;
213
+ /** For number: min value. For date: the earliest day, `YYYY-MM-DD`. */
214
+ min?: number | string;
215
+ /** For number: max value. For date: the latest day. */
216
+ max?: number | string;
204
217
  }
205
218
  /** Configuration for expandable row detail panel */
206
219
  export interface RowDetailConfig<TRow> {
@@ -270,10 +283,11 @@ export interface TreeDataConfig<TRow> {
270
283
  selection?: 'self' | 'cascade';
271
284
  }
272
285
  /**
273
- * The four editors the grid draws for itself. A column wanting anything else — a date picker, a colour,
274
- * a lookup against a table — declares `EditCell` instead and renders it, driven by the same model.
286
+ * The editors the grid draws for itself — `date`, `time` and `datetime` are a `DateField` in the cell. A column
287
+ * wanting anything else — a colour, a lookup against a table — declares `EditCell` instead and renders it,
288
+ * driven by the same model.
275
289
  */
276
- export type CellEditorType = 'text' | 'number' | 'checkbox' | 'select';
290
+ export type CellEditorType = 'text' | 'number' | 'checkbox' | 'select' | 'date' | 'time' | 'datetime';
277
291
  /** One option of a `select` editor. `value` is what the cell holds; `label` is what the list shows. */
278
292
  export interface CellEditorOption {
279
293
  value: string | number | boolean | null;
@@ -288,9 +302,17 @@ export interface CellEditorConfig<TRow> {
288
302
  placeholder?: string;
289
303
  /** `number` only, handed to the input as it stands. */
290
304
  step?: number;
291
- min?: number;
292
- max?: number;
305
+ /** A number for `number`; an ISO string for the date editors, whose value outside it is marked invalid. */
306
+ min?: number | string;
307
+ max?: number | string;
308
+ /** `datetime` only: whose wall clock it is typed on. Default the reader's; `'none'` for no zone. */
309
+ zone?: ZoneInput | 'none';
293
310
  }
311
+ /**
312
+ * How a column writes a date: `'date'`, `'time'`, `'datetime'`, `'relative'` (`3 days ago`), or `Intl` options
313
+ * with a `zone`. In the reader's language and on their wall clock, like `<DateTime>`.
314
+ */
315
+ export type ColumnDateFormat = 'date' | 'time' | 'datetime' | 'relative' | Omit<FormatOptions, 'locale'>;
294
316
  /** Whether a column can be edited: every row of it, or the rows a predicate says. */
295
317
  export type ColumnEditable<TRow> = boolean | ((row: TRow) => boolean);
296
318
  /**
@@ -466,6 +488,25 @@ export interface DataGridHandle {
466
488
  */
467
489
  clearEdits(): void;
468
490
  }
491
+ /**
492
+ * Where a column goes in a list item, when the grid draws itself as a list. `title` is the item's name,
493
+ * `kicker` a small line above it (an id, a date), `subtitle` a line under it, `end` the one value opposite
494
+ * the title (a total, a status), `field` a labelled value, `detail` only the record view, `hidden` nowhere.
495
+ */
496
+ export type ListRole = 'title' | 'kicker' | 'subtitle' | 'end' | 'field' | 'detail' | 'hidden';
497
+ /** How the grid draws itself: a table, a list, or whichever its own width suits. */
498
+ export type DataGridLayout = 'auto' | 'table' | 'list';
499
+ /** The list layout's settings. */
500
+ export interface ListConfig {
501
+ /** The grid's own width, in px, below which `layout: 'auto'` draws a list. Default: 576 (36rem). */
502
+ breakpoint?: number;
503
+ /** How many `field`s an item shows before the rest wait for the record view. Default: 4. */
504
+ fields?: number;
505
+ /** How many items one "Show more" adds. Default: 20. A paginated grid draws its page instead. */
506
+ batchSize?: number;
507
+ /** Whether pressing an item opens the record view, every column of one row with a pager. Default: true. */
508
+ recordView?: boolean;
509
+ }
469
510
  export interface ColumnType<TRow> {
470
511
  key: Key;
471
512
  header?: string;
@@ -504,6 +545,11 @@ export interface ColumnType<TRow> {
504
545
  * numbers gets a numeric keypad without being told.
505
546
  */
506
547
  editor?: CellEditorType | CellEditorConfig<TRow>;
548
+ /**
549
+ * Writes the column's values as dates, in the reader's language and zone — an ISO string or a `Date`. A `Date`
550
+ * is written as a date-time without being told, since it cannot be rendered as it stands.
551
+ */
552
+ dateFormat?: ColumnDateFormat;
507
553
  /**
508
554
  * An editor of your own, for what the four built-in ones do not cover. It is handed the cell, and the
509
555
  * cell carries the draft value and the two ways out (`commitEdit`, `cancelEdit`) — so a custom editor
@@ -522,6 +568,11 @@ export interface ColumnType<TRow> {
522
568
  flexible?: boolean;
523
569
  /** Control the header context menu. false hides it entirely. Object controls individual sections. Inherits from GridDefinition.contextMenu if undefined. */
524
570
  contextMenu?: boolean | ContextMenuConfig;
571
+ /**
572
+ * Where this column goes in a list item. Default: the first column is the title, the first end-aligned one
573
+ * sits opposite it, the next `def.list.fields` are fields and the rest wait for the record view.
574
+ */
575
+ list?: ListRole;
525
576
  }
526
577
  export interface GridDefinition<TRow> {
527
578
  rowKey?: KeysMatching<TRow, Key> | ((rowData: TRow) => Key);
@@ -553,6 +604,14 @@ export interface GridDefinition<TRow> {
553
604
  */
554
605
  rangeSelection?: boolean;
555
606
  rowHeight?: number;
607
+ /**
608
+ * How the grid draws itself. `'auto'` (default) is a table, and a list once the grid itself is narrower
609
+ * than `def.list.breakpoint` — its own width rather than the viewport's, so a grid in a narrow column of
610
+ * a wide page reads as a list too. `'table'` and `'list'` choose one for good.
611
+ */
612
+ layout?: DataGridLayout;
613
+ /** The list layout's settings: the breakpoint, how many fields an item shows, the record view. */
614
+ list?: ListConfig;
556
615
  /** Number of visible rows. Set to 'all' to render all rows without virtualization or vertical scrollbar. */
557
616
  visibleRowsCount?: number | 'all';
558
617
  topBar?: boolean;
@@ -1,4 +1,4 @@
1
- import { ColumnAggregate, ColumnEditable, ColumnFilterConfig, ColumnType, ContextMenuConfig, FilterValue, Key, NumberFilterValue, PinPosition, PinPositionInput, SortDirection } from '../contracts/dataGridContract';
1
+ import { ColumnAggregate, ColumnEditable, ColumnFilterConfig, ColumnType, ContextMenuConfig, DateFilterValue, 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. */
@@ -80,6 +80,8 @@ export default class ColumnModel<TRow> {
80
80
  }[];
81
81
  setTextFilter(value: string): void;
82
82
  setNumberFilter(operator: NumberFilterValue['operator'], value: string | number, valueTo?: string | number): void;
83
+ /** A day, before or after one, or a span — `null` for a value still being typed, which is no filter yet. */
84
+ setDateFilter(operator: DateFilterValue['operator'], value: string | null, valueTo?: string | null): void;
83
85
  setMultiselectFilter(values: (string | number | boolean | null)[]): void;
84
86
  clearFilter(): void;
85
87
  /**
@@ -1,8 +1,10 @@
1
- import { CellEdit, CellEditorConfig, Key } from '../contracts/dataGridContract';
1
+ import { CellEdit, CellEditorConfig, CellEditorType, Key } from '../contracts/dataGridContract';
2
2
  import { default as ColumnModel } from './columnModel';
3
3
  import { default as GridModel } from './gridModel';
4
4
  import { RangeBounds } from './rangeModel';
5
5
  import { default as RowModel } from './rowModel';
6
+ /** Whether an editor is a `DateField`. */
7
+ export declare function isDateEditor(type: CellEditorType): boolean;
6
8
  /** A key that starts an edit by replacing the value: one printable character, unmodified. */
7
9
  export declare function isTypingKey(event: React.KeyboardEvent): boolean;
8
10
  /**
@@ -9,6 +9,7 @@ import { default as EditModel } from './editModel';
9
9
  import { default as ExportModel } from './exportModel';
10
10
  import { default as FilterModel } from './filterModel';
11
11
  import { default as GroupRowModel } from './groupRowModel';
12
+ import { default as ListModel } from './listModel';
12
13
  import { DataGridLocaleText } from './localeText';
13
14
  import { default as PaginationModel } from './paginationModel';
14
15
  import { default as RangeModel } from './rangeModel';
@@ -239,6 +240,8 @@ export default class GridModel<TRow> {
239
240
  readonly edits: EditModel<TRow>;
240
241
  /** The current cell, the block of cells marked around it, and what the clipboard is written from. */
241
242
  readonly range: RangeModel<TRow>;
243
+ /** The grid drawn as a list, for a phone. */
244
+ readonly list: ListModel<TRow>;
242
245
  /**
243
246
  * Throw the fetched blocks away and ask for them again. The grid invalidates on its own whenever it
244
247
  * changes the query; this is for the half it cannot see — a filter of the page's own, a row somebody
@@ -0,0 +1,129 @@
1
+ import { FilterValue, Key } from '../contracts/dataGridContract';
2
+ import { default as ColumnModel } from './columnModel';
3
+ import { default as GridModel } from './gridModel';
4
+ import { default as GroupRowModel } from './groupRowModel';
5
+ import { default as RowModel } from './rowModel';
6
+ /** 36rem: where Polaris, Roselli and the Scottish Government's tables all give up on columns. */
7
+ export declare const DEFAULT_LIST_BREAKPOINT = 576;
8
+ /** How many labelled values an item shows before the rest wait for the record view. */
9
+ export declare const DEFAULT_LIST_FIELDS = 4;
10
+ /** How many items one "Show more" adds — a couple of screens of phone. */
11
+ export declare const DEFAULT_LIST_BATCH = 20;
12
+ /** Which columns an item draws where. Every list is in column order. */
13
+ export interface ListItemLayout<TRow> {
14
+ title?: ColumnModel<TRow>;
15
+ kicker?: ColumnModel<TRow>;
16
+ subtitle: ColumnModel<TRow>[];
17
+ end?: ColumnModel<TRow>;
18
+ fields: ColumnModel<TRow>[];
19
+ /** The columns only the record view shows. */
20
+ detail: ColumnModel<TRow>[];
21
+ }
22
+ /** One column filter that is set, the way its chip says it. */
23
+ export interface ActiveFilterChip<TRow> {
24
+ column: ColumnModel<TRow>;
25
+ label: string;
26
+ value: string;
27
+ }
28
+ export type ListSheet = 'sort' | 'filter';
29
+ /** One entry of the list, and where it sits in the grid's own rows — which is what a record is opened at. */
30
+ export interface ListEntry<TRow> {
31
+ row: RowModel<TRow> | GroupRowModel<TRow>;
32
+ index: number;
33
+ }
34
+ /**
35
+ * The grid drawn for a phone: a list of items instead of a table. It decides when the grid switches, which
36
+ * column goes where in an item, how many items are drawn, which sheet is open, whether the list is selecting,
37
+ * and which row the record view is on. The rows, the filters and the sort stay the grid's — an item is another
38
+ * drawing of the same row, so whatever a table does to a row it does to an item.
39
+ */
40
+ export default class ListModel<TRow> {
41
+ readonly grid: GridModel<TRow>;
42
+ constructor(grid: GridModel<TRow>);
43
+ private get config();
44
+ get breakpoint(): number;
45
+ private _width;
46
+ /** The grid's own width in px, 0 until something has measured it — which a server render never does. */
47
+ get width(): number;
48
+ /** Whether the grid draws a list. `auto` decides on the grid's own width rather than the viewport's. */
49
+ get active(): boolean;
50
+ /** Report the grid's width. Only crossing the breakpoint redraws anything. */
51
+ setWidth: (width: number) => void;
52
+ /**
53
+ * Which column goes where. A column's `list` role wins; otherwise the first data column is the title, the
54
+ * first end-aligned one — a total, an amount — sits opposite it, the next few are fields and the rest wait
55
+ * for the record view. A grouped column is its group's header, so it is not repeated in every item.
56
+ */
57
+ readonly layout: import('../../../utils/memo').Memo<{
58
+ title: ColumnModel<TRow> | undefined;
59
+ kicker: ColumnModel<TRow> | undefined;
60
+ subtitle: ColumnModel<TRow>[];
61
+ end: ColumnModel<TRow> | undefined;
62
+ fields: ColumnModel<TRow>[];
63
+ detail: ColumnModel<TRow>[];
64
+ }>;
65
+ /** Every column the record view lists, in column order. */
66
+ get recordColumns(): ColumnModel<TRow>[];
67
+ private get batch();
68
+ private _limit?;
69
+ /**
70
+ * What the list is a list of. A different answer is a different list, so "Show more" starts again from one
71
+ * batch — while opening a group or a detail panel changes the rows and not the question, and keeps what the
72
+ * reader has already scrolled through.
73
+ */
74
+ private get query();
75
+ /** Where the list is cut: whole batches, or nowhere when the grid is paginated, since a page is the batch. */
76
+ private get count();
77
+ private _more;
78
+ /**
79
+ * The entries drawn now, up to the cut — a detail panel is drawn inside its own item. A walk from the top
80
+ * rather than a filter, because a datasource's list is lazy and walking all of it is a model per row.
81
+ */
82
+ get visibleItems(): ListEntry<TRow>[];
83
+ /** Whether entries are left past the cut. Read after `visibleItems`, which is what measures it. */
84
+ get hasMore(): boolean;
85
+ /** How many entries the next "Show more" adds. Read after `visibleItems`. */
86
+ get nextBatch(): number;
87
+ showMore: () => void;
88
+ private _selecting;
89
+ /**
90
+ * Whether a press on an item ticks it rather than opening it. Selection is a mode on a phone — iOS's edit
91
+ * mode, Android's contextual bar — because a checkbox on every item is a target a thumb hits by accident.
92
+ */
93
+ get selecting(): boolean;
94
+ setSelecting: (selecting: boolean) => void;
95
+ /** The id of a row's checkbox, which the item's title is the label of — so a press anywhere on the item ticks it. */
96
+ checkboxId(key: Key): string;
97
+ private _sheet;
98
+ /** Which bottom sheet is open — the sort or the filters — or `null`. */
99
+ get sheet(): ListSheet | null;
100
+ openSheet: (sheet: ListSheet | null) => void;
101
+ /** The columns the sort sheet offers. */
102
+ get sortableColumns(): ColumnModel<TRow>[];
103
+ /** The column the grid is sorted by, when it is one the sheet offers. */
104
+ get sortedColumn(): ColumnModel<TRow> | undefined;
105
+ /** The columns the filter sheet offers. */
106
+ get filterableColumns(): ColumnModel<TRow>[];
107
+ /** Every column filter that is set, the way a chip says it. */
108
+ get activeFilters(): ActiveFilterChip<TRow>[];
109
+ /** A filter in words: `“ali”`, `≥ 30`, `20–40`, `Japan, Spain +2`. */
110
+ describe(column: ColumnModel<TRow>, filter: FilterValue): string;
111
+ private _record;
112
+ /** The row the record view is showing, or `undefined` while it is shut. */
113
+ get record(): RowModel<TRow> | undefined;
114
+ /** Whether pressing an item opens its record. */
115
+ get recordViewEnabled(): boolean;
116
+ /** Open the record view on a row, at its index in the grid's rows. */
117
+ openRecord: (row: RowModel<TRow>, index: number) => void;
118
+ closeRecord: () => void;
119
+ private neighbour;
120
+ get hasPreviousRecord(): boolean;
121
+ get hasNextRecord(): boolean;
122
+ /** Step to the record before or after this one, past group headers and detail panels. */
123
+ stepRecord: (step: 1 | -1) => void;
124
+ /** Where the record sits among the rows — "3 of 40" — counting rows, not group headers. */
125
+ get recordPosition(): {
126
+ position: number;
127
+ total: number;
128
+ } | undefined;
129
+ }
@@ -60,6 +60,10 @@ export interface DataGridLocaleText {
60
60
  filterSelectAll: string;
61
61
  /** How a multiselect filter lists a `null` value. */
62
62
  filterEmptyValue: string;
63
+ /** What a `true` cell is read out and listed as; it is drawn as a check. */
64
+ booleanTrue: string;
65
+ /** What a `false` cell is read out and listed as; it is drawn as a cross. */
66
+ booleanFalse: string;
63
67
  /** What an empty grid shows when there is no `noDataComponent`. */
64
68
  noRows: string;
65
69
  loadingRows: string;
@@ -101,6 +105,38 @@ export interface DataGridLocaleText {
101
105
  previousPage: string;
102
106
  nextPage: string;
103
107
  lastPage: string;
108
+ /** The sort button before anything is sorted, and the sort sheet's title. */
109
+ sortBy: string;
110
+ /** The sort button once a column is sorted: the column and the direction. */
111
+ sortedBy: (column: string, descending: boolean) => string;
112
+ ascending: string;
113
+ descending: string;
114
+ /** The filters button and the filter sheet's title. */
115
+ filters: string;
116
+ /** The filters button's accessible name, with how many are set. */
117
+ filtersLabel: (count: number) => string;
118
+ /** The filter sheet's main button: it closes the sheet and says how many rows are left. */
119
+ showRows: (count: number) => string;
120
+ /** What closes a sheet or the record view. */
121
+ close: string;
122
+ /** The button under the cards: how many the next press adds. */
123
+ showMore: (count: number) => string;
124
+ /** Under the cards: how many of the rows are drawn. */
125
+ shownCount: (shown: number, total: number) => string;
126
+ /** The record view's pager: "3 of 40". */
127
+ recordPosition: (position: number, total: number) => string;
128
+ previousRow: string;
129
+ nextRow: string;
130
+ /** The heading over a `rowDetail` panel in the record view. */
131
+ details: string;
132
+ /** The toggle that puts the list into selecting, where a press ticks a row rather than opening it. */
133
+ selectRows: string;
134
+ clearSearch: string;
135
+ /** The record view's button beside an editable value; its name is `editCell`. */
136
+ edit: string;
137
+ /** The list's selection bar: how many rows are ticked, short enough for a phone's width. */
138
+ selectedRows: (count: number) => string;
139
+ selectAll: string;
104
140
  /** What the live region says when the selection changes. */
105
141
  selectionAnnouncement: (selected: number, total: number) => string;
106
142
  }
@@ -59,7 +59,5 @@ export default class ViewportModel<TRow> {
59
59
  get emptyHeight(): number;
60
60
  /** Where a row sits inside the scrolled body — what a keyboard jump scrolls to. */
61
61
  rowTop(index: number): number;
62
- /** Binary search for the first row whose offset is <= scrollTop (variable-height rows). */
63
- private findStartIndex;
64
62
  window(scrollTop: number, direction?: ScrollDirection): ViewportWindow;
65
63
  }
@@ -0,0 +1,17 @@
1
+ import { default as DataGridDateParts } from './components/dataGridDateParts';
2
+ type DateParts = typeof DataGridDateParts;
3
+ /**
4
+ * Fetch the grid's date parts — the formatter, the `DateField` editor and the date filters. A chunk of its own,
5
+ * since a grid with no dates in it should not carry a date library, so it is asked for the first time a cell,
6
+ * an editor or a filter needs one.
7
+ */
8
+ export declare function loadDateParts(): Promise<DateParts>;
9
+ /** The parts if they have arrived — what a model asks, since it cannot wait for them. */
10
+ export declare function dateParts(): DateParts | undefined;
11
+ /**
12
+ * The parts once they are here, or `undefined` while the cell goes on showing the raw value. Always `undefined`
13
+ * on the first render, which is what a server rendered too; a layout effect swaps them in before the paint when
14
+ * they are already loaded. No `React.lazy`, for the reason `useListLayout` gives.
15
+ */
16
+ export default function useDateParts(active: boolean): DateParts | undefined;
17
+ export {};
@@ -0,0 +1,13 @@
1
+ import { default as DataGridList } from './components/dataGridList';
2
+ type ListLayout = typeof DataGridList;
3
+ /**
4
+ * Fetch the list layout. It is a chunk of its own — the sheets, the record view and the `<dialog>` under them
5
+ * are 10 KB gzipped a wide screen never draws — so it is asked for the first time a grid is narrow.
6
+ */
7
+ export declare function loadListLayout(): Promise<ListLayout>;
8
+ /**
9
+ * The list layout's component once it has arrived, or `undefined` while the grid should go on drawing its
10
+ * table. No `React.lazy`: a Suspense boundary is the one thing a React 16 or 17 server cannot render.
11
+ */
12
+ export default function useListLayout(active: boolean): ListLayout | undefined;
13
+ export {};