@zuilib/data-grid 0.3.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.
@@ -0,0 +1,65 @@
1
+ import { e as DataGridState } from './state-9r5WYKo_.js';
2
+ import '@tanstack/react-table';
3
+ import '@zuilib/components/button';
4
+
5
+ /**
6
+ * The grid state as a plain request object: what most list endpoints take.
7
+ * `page` is 1-based; `filters` is keyed by column id with the raw filter
8
+ * value (a string for a text filter, a string array for a facet filter, a
9
+ * `{ from, to }` for a date range). `allMatching` is the selection bar's
10
+ * "Select all N": the server applies the selection action to every matching row.
11
+ */
12
+ interface DataGridQuery {
13
+ page: number;
14
+ pageSize: number;
15
+ sort: {
16
+ id: string;
17
+ desc: boolean;
18
+ }[];
19
+ filters: Record<string, unknown>;
20
+ search: string;
21
+ allMatching: boolean;
22
+ }
23
+ /** The keys of the state a server request depends on. */
24
+ type DataGridServerState = Pick<DataGridState, 'pagination' | 'sorting' | 'columnFilters' | 'search' | 'allMatching'>;
25
+ /** The keys of the state that describe a saved view of the columns. */
26
+ type DataGridColumnState = Pick<DataGridState, 'columnVisibility' | 'columnOrder' | 'columnPinning' | 'columnSizing'>;
27
+ /**
28
+ * Only the keys a request depends on. Selection, visibility, order, pinning,
29
+ * sizing and expansion are left out, so a UI-only change gives a state that
30
+ * is deep-equal to the previous one.
31
+ */
32
+ declare function toServerState(state: Partial<DataGridState>): DataGridServerState;
33
+ /**
34
+ * The request for the given state. Pure: depends only on `toServerState(state)`.
35
+ * `filters` is keyed in column id order, whatever order the filters were
36
+ * applied in, so `toQueryKey` is the same for the same set of filters.
37
+ */
38
+ declare function toQuery(state: Partial<DataGridState>): DataGridQuery;
39
+ /**
40
+ * A string that changes only when the request would: the same for two states
41
+ * that differ in selection, visibility, order, pinning, sizing or expansion,
42
+ * or in the order their column filters were applied.
43
+ * Use it as the dependency of the effect (or the query cache key) that fetches,
44
+ * so a checkbox, a hidden column or a resize never refetches.
45
+ */
46
+ declare function toQueryKey(state: Partial<DataGridState>): string;
47
+ /**
48
+ * The inverse: the grid state a request describes (a URL restore, a saved view).
49
+ * The input is untrusted, so every key is checked for shape and never throws:
50
+ * `page` and `pageSize` must be positive integers (else the first page / the
51
+ * default page size); `sort` must be an array, of which only the entries with
52
+ * a string `id` are kept; `filters` must be a plain object; `search` a string.
53
+ * Filter values and sort ids are otherwise taken as they are: the grid does
54
+ * not know the columns here, so unknown ids reach the state unchanged.
55
+ */
56
+ declare function fromQuery(query: Partial<DataGridQuery>): DataGridServerState;
57
+ /**
58
+ * The column layout for a saved view: visibility, order, pinning and sizing,
59
+ * without the grid's own selection / expand columns (the grid puts them back).
60
+ */
61
+ declare function toColumnState(state: Partial<DataGridState>): DataGridColumnState;
62
+ /** The inverse: the state keys a saved view restores; a missing key takes its default. */
63
+ declare function fromColumnState(saved: Partial<DataGridColumnState>): DataGridColumnState;
64
+
65
+ export { type DataGridColumnState, type DataGridQuery, type DataGridServerState, DataGridState, fromColumnState, fromQuery, toColumnState, toQuery, toQueryKey, toServerState };
@@ -0,0 +1,105 @@
1
+ // src/state.ts
2
+ var DEFAULT_PAGE_SIZE = 25;
3
+ var defaultDataGridState = {
4
+ pagination: { pageIndex: 0, pageSize: DEFAULT_PAGE_SIZE },
5
+ sorting: [],
6
+ columnFilters: [],
7
+ search: "",
8
+ columnVisibility: {},
9
+ columnOrder: [],
10
+ columnPinning: { start: [], end: [] },
11
+ rowSelection: {},
12
+ expanded: {},
13
+ allMatching: false
14
+ };
15
+
16
+ // src/server-adapter.ts
17
+ var INTERNAL_COLUMN_IDS = /* @__PURE__ */ new Set(["__select", "__expand"]);
18
+ function toServerState(state) {
19
+ const s = { ...defaultDataGridState, ...state };
20
+ return {
21
+ pagination: s.pagination,
22
+ sorting: s.sorting,
23
+ columnFilters: s.columnFilters,
24
+ search: s.search,
25
+ allMatching: s.allMatching ?? false
26
+ };
27
+ }
28
+ var isEmptyFilter = (value) => value === void 0 || value === "" || Array.isArray(value) && value.length === 0;
29
+ function toQuery(state) {
30
+ const s = toServerState(state);
31
+ const filters = {};
32
+ const active = s.columnFilters.filter((filter) => !isEmptyFilter(filter.value));
33
+ for (const filter of [...active].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) {
34
+ filters[filter.id] = filter.value;
35
+ }
36
+ return {
37
+ page: s.pagination.pageIndex + 1,
38
+ pageSize: s.pagination.pageSize,
39
+ sort: s.sorting.map(({ id, desc }) => ({ id, desc })),
40
+ filters,
41
+ search: s.search,
42
+ allMatching: s.allMatching ?? false
43
+ };
44
+ }
45
+ function toQueryKey(state) {
46
+ return JSON.stringify(toQuery(state));
47
+ }
48
+ var isPositiveInteger = (value) => typeof value === "number" && Number.isInteger(value) && value > 0;
49
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
50
+ function toSortEntry(entry) {
51
+ if (!isPlainObject(entry) || typeof entry.id !== "string" || entry.id === "") return null;
52
+ return { id: entry.id, desc: entry.desc === true };
53
+ }
54
+ function fromQuery(query) {
55
+ const pageSize = isPositiveInteger(query.pageSize) ? query.pageSize : defaultDataGridState.pagination.pageSize;
56
+ const page = isPositiveInteger(query.page) ? query.page : 1;
57
+ const sorting = [];
58
+ if (Array.isArray(query.sort)) {
59
+ for (const entry of query.sort) {
60
+ const sort = toSortEntry(entry);
61
+ if (sort) sorting.push(sort);
62
+ }
63
+ }
64
+ const filters = isPlainObject(query.filters) ? query.filters : {};
65
+ return {
66
+ pagination: { pageIndex: page - 1, pageSize },
67
+ sorting,
68
+ columnFilters: Object.entries(filters).filter(([, value]) => !isEmptyFilter(value)).map(([id, value]) => ({ id, value })),
69
+ search: typeof query.search === "string" ? query.search : "",
70
+ allMatching: query.allMatching === true
71
+ };
72
+ }
73
+ function toColumnState(state) {
74
+ const s = { ...defaultDataGridState, ...state };
75
+ const own = (id) => !INTERNAL_COLUMN_IDS.has(id);
76
+ const visibility = {};
77
+ for (const [id, visible] of Object.entries(s.columnVisibility)) if (own(id)) visibility[id] = visible;
78
+ const sizing = {};
79
+ for (const [id, size] of Object.entries(s.columnSizing ?? {})) if (own(id)) sizing[id] = size;
80
+ return {
81
+ columnVisibility: visibility,
82
+ columnOrder: s.columnOrder.filter(own),
83
+ columnPinning: { start: (s.columnPinning.start ?? []).filter(own), end: (s.columnPinning.end ?? []).filter(own) },
84
+ columnSizing: sizing
85
+ };
86
+ }
87
+ function fromColumnState(saved) {
88
+ const visibility = { ...saved.columnVisibility };
89
+ const order = [...saved.columnOrder ?? []];
90
+ const pinning = { start: [...saved.columnPinning?.start ?? []], end: [...saved.columnPinning?.end ?? []] };
91
+ return {
92
+ columnVisibility: visibility,
93
+ columnOrder: order,
94
+ columnPinning: pinning,
95
+ columnSizing: { ...saved.columnSizing }
96
+ };
97
+ }
98
+ export {
99
+ fromColumnState,
100
+ fromQuery,
101
+ toColumnState,
102
+ toQuery,
103
+ toQueryKey,
104
+ toServerState
105
+ };
@@ -0,0 +1,63 @@
1
+ import { PaginationState, SortingState, ColumnFiltersState, VisibilityState, ColumnOrderState, RowSelectionState, ExpandedState, ColumnSizingState } from '@tanstack/react-table';
2
+ import { ButtonVariant, ButtonTone } from '@zuilib/components/button';
3
+
4
+ /**
5
+ * Which columns stick to each edge. Logical directions: `start` is the
6
+ * inline start (left in LTR, right in RTL). Mapped to TanStack's
7
+ * `left`/`right` internally.
8
+ */
9
+ interface DataGridColumnPinning {
10
+ start: string[];
11
+ end: string[];
12
+ }
13
+ /**
14
+ * Everything the grid can change. The consumer owns it: every interaction
15
+ * calls `onStateChange` with the whole next state, and the grid renders
16
+ * whatever comes back (a server round-trip in between is the point).
17
+ */
18
+ interface DataGridState {
19
+ pagination: PaginationState;
20
+ sorting: SortingState;
21
+ columnFilters: ColumnFiltersState;
22
+ /** The free-text search (the toolbar's search field). */
23
+ search: string;
24
+ columnVisibility: VisibilityState;
25
+ columnOrder: ColumnOrderState;
26
+ columnPinning: DataGridColumnPinning;
27
+ rowSelection: RowSelectionState;
28
+ /** Expanded rows, keyed by row id. UI-only: `toQuery` leaves it out. */
29
+ expanded: ExpandedState;
30
+ /**
31
+ * "Select all N": every row matching the current query is selected, not
32
+ * only the ones on this page. Set by the selection bar; cleared by any
33
+ * other selection change. `toQuery` passes it on, the server acts on it.
34
+ */
35
+ allMatching?: boolean;
36
+ /**
37
+ * Column widths in px, keyed by column id. Optional: left out, the grid
38
+ * keeps the widths itself; passed (even `{}`), resizes go out through
39
+ * `onStateChange` so they can be persisted. UI-only: `toQuery` leaves it out.
40
+ */
41
+ columnSizing?: ColumnSizingState;
42
+ }
43
+ declare const DEFAULT_PAGE_SIZE = 25;
44
+ declare const defaultDataGridState: DataGridState;
45
+ /** Fills the keys a consumer left out, so the grid always sees a full state. */
46
+ declare function resolveDataGridState(state: Partial<DataGridState> | undefined): DataGridState;
47
+ type DataGridDensity = 'compact' | 'comfortable';
48
+ interface DataGridSelectionActionContext {
49
+ /** `true` when "Select all N" is on: act on every row matching the query, not only `selectedIds`. */
50
+ allMatching: boolean;
51
+ /** The rows matching the query (`rowCount`), the size of the set when `allMatching` is on. */
52
+ rowCount: number;
53
+ }
54
+ /** A button in the bar that appears while rows are selected. */
55
+ interface DataGridSelectionAction {
56
+ id: string;
57
+ label: string;
58
+ variant?: ButtonVariant;
59
+ tone?: ButtonTone;
60
+ onSelect: (selectedIds: string[], context: DataGridSelectionActionContext) => void;
61
+ }
62
+
63
+ export { DEFAULT_PAGE_SIZE as D, type DataGridColumnPinning as a, type DataGridDensity as b, type DataGridSelectionAction as c, type DataGridSelectionActionContext as d, type DataGridState as e, defaultDataGridState as f, resolveDataGridState as r };
@@ -0,0 +1,97 @@
1
+ import { ColumnDef, PaginationState, SortingState, ColumnFiltersState, VisibilityState, ColumnOrderState, ColumnPinningState, RowSelectionState, ExpandedState, ColumnSizingState } from '@tanstack/react-table';
2
+
3
+ /**
4
+ * Everything the grid can change. The consumer owns it: every interaction
5
+ * calls `onStateChange` with the whole next state, and the grid renders
6
+ * whatever comes back (a server round-trip in between is the point).
7
+ */
8
+ interface DataGridState {
9
+ pagination: PaginationState;
10
+ sorting: SortingState;
11
+ columnFilters: ColumnFiltersState;
12
+ globalFilter: string;
13
+ columnVisibility: VisibilityState;
14
+ columnOrder: ColumnOrderState;
15
+ columnPinning: ColumnPinningState;
16
+ rowSelection: RowSelectionState;
17
+ /** Expanded rows, keyed by row id. UI-only: `toQuery` leaves it out. */
18
+ expanded: ExpandedState;
19
+ /**
20
+ * Column widths in px, keyed by column id. Optional: left out, the grid
21
+ * keeps the widths itself; passed (even `{}`), resizes go out through
22
+ * `onStateChange` so they can be persisted. UI-only: `toQuery` leaves it out.
23
+ */
24
+ columnSizing?: ColumnSizingState;
25
+ }
26
+ declare const DEFAULT_PAGE_SIZE = 25;
27
+ declare const defaultDataGridState: DataGridState;
28
+ /** Fills the keys a consumer left out, so the grid always sees a full state. */
29
+ declare function resolveDataGridState(state: Partial<DataGridState> | undefined): DataGridState;
30
+ type DataGridAlign = 'start' | 'center' | 'end';
31
+ /** A text filter: one string, matched however the server matches it. */
32
+ interface DataGridTextFilter {
33
+ type: 'text';
34
+ placeholder?: string;
35
+ }
36
+ /** A facet filter: a list of options, of which any number may be picked. */
37
+ interface DataGridSelectFilter {
38
+ type: 'select';
39
+ options: readonly {
40
+ value: string;
41
+ label?: string;
42
+ }[];
43
+ }
44
+ /** A date range: ISO `YYYY-MM-DD` bounds, either side optional. */
45
+ interface DataGridDateRangeFilter {
46
+ type: 'date-range';
47
+ }
48
+ type DataGridFilter = DataGridTextFilter | DataGridSelectFilter | DataGridDateRangeFilter;
49
+ interface DataGridDateRange {
50
+ from?: string;
51
+ to?: string;
52
+ }
53
+ /** The ZUI extras on a TanStack column definition. */
54
+ interface DataGridColumnExtras {
55
+ /** Double-click or Enter on a cell turns it into an input; see `onCellEdit`. */
56
+ enableInlineEdit?: boolean;
57
+ /** Horizontal alignment of the head and the cells; `end` for numbers. */
58
+ align?: DataGridAlign;
59
+ /** Initial width in px (TanStack `size`); the user can resize from there. */
60
+ width?: number;
61
+ /** Declares the column's filter popover. */
62
+ filter?: DataGridFilter;
63
+ }
64
+ type DataGridColumnDef<TData, TValue = unknown> = ColumnDef<TData, TValue> & DataGridColumnExtras;
65
+ /** The extras may also be declared on `meta` (the TanStack way of extending a column). */
66
+ interface DataGridColumnMeta extends DataGridColumnExtras {
67
+ /** The column's name in the column manager, the filter chips and the pin labels, when `header` is not a string. */
68
+ label?: string;
69
+ }
70
+ /** The grid's own strings, overridable for another language. */
71
+ interface DataGridLabels {
72
+ /** @default 'Pin left' */
73
+ pinLeft: string;
74
+ /** @default 'Pin right' */
75
+ pinRight: string;
76
+ /** @default 'Unpin' */
77
+ unpin: string;
78
+ /** @default 'Expand row' */
79
+ expandRow: string;
80
+ /** @default 'Collapse row' */
81
+ collapseRow: string;
82
+ }
83
+ declare const defaultDataGridLabels: DataGridLabels;
84
+ interface DataGridCellEdit {
85
+ rowId: string;
86
+ columnId: string;
87
+ value: string;
88
+ }
89
+ interface DataGridBulkAction {
90
+ id: string;
91
+ label: string;
92
+ variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost';
93
+ onAction: (selectedIds: string[]) => void;
94
+ }
95
+ type DataGridDensity = 'compact' | 'comfortable';
96
+
97
+ export { type DataGridState as D, type DataGridDensity as a, type DataGridCellEdit as b, type DataGridBulkAction as c, type DataGridLabels as d, DEFAULT_PAGE_SIZE as e, type DataGridAlign as f, type DataGridColumnDef as g, type DataGridColumnExtras as h, type DataGridColumnMeta as i, type DataGridDateRange as j, type DataGridDateRangeFilter as k, type DataGridFilter as l, type DataGridSelectFilter as m, type DataGridTextFilter as n, defaultDataGridLabels as o, defaultDataGridState as p, resolveDataGridState as r };
@@ -0,0 +1,192 @@
1
+ import { ColumnDef, PaginationState, SortingState, ColumnFiltersState, VisibilityState, ColumnOrderState, ColumnPinningState, RowSelectionState, ExpandedState, ColumnSizingState } from '@tanstack/react-table';
2
+
3
+ /**
4
+ * Everything the grid can change. The consumer owns it: every interaction
5
+ * calls `onStateChange` with the whole next state, and the grid renders
6
+ * whatever comes back (a server round-trip in between is the point).
7
+ */
8
+ interface DataGridState {
9
+ pagination: PaginationState;
10
+ sorting: SortingState;
11
+ columnFilters: ColumnFiltersState;
12
+ globalFilter: string;
13
+ columnVisibility: VisibilityState;
14
+ columnOrder: ColumnOrderState;
15
+ columnPinning: ColumnPinningState;
16
+ rowSelection: RowSelectionState;
17
+ /** Expanded rows, keyed by row id. UI-only: `toQuery` leaves it out. */
18
+ expanded: ExpandedState;
19
+ /**
20
+ * "Select all N": every row matching the current query is selected, not
21
+ * only the ones on this page. Set by the bulk bar; cleared by any other
22
+ * selection change. `toQuery` passes it on, the server acts on it.
23
+ */
24
+ allMatching?: boolean;
25
+ /**
26
+ * Column widths in px, keyed by column id. Optional: left out, the grid
27
+ * keeps the widths itself; passed (even `{}`), resizes go out through
28
+ * `onStateChange` so they can be persisted. UI-only: `toQuery` leaves it out.
29
+ */
30
+ columnSizing?: ColumnSizingState;
31
+ }
32
+ declare const DEFAULT_PAGE_SIZE = 25;
33
+ declare const defaultDataGridState: DataGridState;
34
+ /** Fills the keys a consumer left out, so the grid always sees a full state. */
35
+ declare function resolveDataGridState(state: Partial<DataGridState> | undefined): DataGridState;
36
+ type DataGridAlign = 'start' | 'center' | 'end';
37
+ /** A text filter: one string, matched however the server matches it. */
38
+ interface DataGridTextFilter {
39
+ type: 'text';
40
+ placeholder?: string;
41
+ }
42
+ /** A facet filter: a list of options, of which any number may be picked. */
43
+ interface DataGridSelectFilter {
44
+ type: 'select';
45
+ options: readonly {
46
+ value: string;
47
+ label?: string;
48
+ }[];
49
+ }
50
+ /** A date range: ISO `YYYY-MM-DD` bounds, either side optional. */
51
+ interface DataGridDateRangeFilter {
52
+ type: 'date-range';
53
+ }
54
+ type DataGridFilter = DataGridTextFilter | DataGridSelectFilter | DataGridDateRangeFilter;
55
+ interface DataGridDateRange {
56
+ from?: string;
57
+ to?: string;
58
+ }
59
+ /** The ZUI extras on a TanStack column definition. */
60
+ interface DataGridColumnExtras {
61
+ /** Double-click or Enter on a cell turns it into an input; see `onCellEdit`. */
62
+ enableInlineEdit?: boolean;
63
+ /** Horizontal alignment of the head and the cells; `end` for numbers. */
64
+ align?: DataGridAlign;
65
+ /** Initial width in px (TanStack `size`); the user can resize from there. */
66
+ width?: number;
67
+ /** Declares the column's filter popover. */
68
+ filter?: DataGridFilter;
69
+ }
70
+ type DataGridColumnDef<TData, TValue = unknown> = ColumnDef<TData, TValue> & DataGridColumnExtras;
71
+ /** The extras may also be declared on `meta` (the TanStack way of extending a column). */
72
+ interface DataGridColumnMeta extends DataGridColumnExtras {
73
+ /** The column's name in the column manager, the filter chips and the pin labels, when `header` is not a string. */
74
+ label?: string;
75
+ }
76
+ /**
77
+ * Every string the grid renders or announces, overridable for another
78
+ * language. A `{name}` placeholder is replaced with the value named.
79
+ */
80
+ interface DataGridLabels {
81
+ /** @default 'Pin left' */
82
+ pinLeft: string;
83
+ /** @default 'Pin right' */
84
+ pinRight: string;
85
+ /** @default 'Unpin' */
86
+ unpin: string;
87
+ /** @default 'Expand row' */
88
+ expandRow: string;
89
+ /** @default 'Collapse row' */
90
+ collapseRow: string;
91
+ /** The sr-only head of the expand column. @default 'Expand' */
92
+ expandColumn: string;
93
+ /** Bulk bar: the count of selected rows. `{count}` is replaced. @default '{count} selected' */
94
+ selectedCount: string;
95
+ /** Bulk bar: the count when every matching row is selected. `{count}` is replaced. @default 'All {count} selected' */
96
+ allMatchingSelected: string;
97
+ /** Bulk bar: the button that selects every matching row. `{count}` is replaced. @default 'Select all {count}' */
98
+ selectAllMatching: string;
99
+ /** @default 'Clear selection' */
100
+ clearSelection: string;
101
+ /** The bulk bar's region name. @default 'Bulk actions' */
102
+ bulkActions: string;
103
+ /** The head checkbox. @default 'Select all rows on this page' */
104
+ selectAllOnPage: string;
105
+ /** A row checkbox. @default 'Select row' */
106
+ selectRow: string;
107
+ /** The footer's `<nav>` name. @default 'Pagination' */
108
+ pagination: string;
109
+ /** @default 'Rows per page' */
110
+ rowsPerPage: string;
111
+ /** The range text while loading. @default 'Loading…' */
112
+ loading: string;
113
+ /** The range text. `{first}`, `{last}` and `{total}` are replaced. @default '{first}–{last} of {total}' */
114
+ range: string;
115
+ /** @default 'First page' */
116
+ firstPage: string;
117
+ /** @default 'Previous page' */
118
+ previousPage: string;
119
+ /** @default 'Next page' */
120
+ nextPage: string;
121
+ /** @default 'Last page' */
122
+ lastPage: string;
123
+ /** The toolbar search field's name. @default 'Search' */
124
+ search: string;
125
+ /** The toolbar search field's placeholder. @default 'Search…' */
126
+ searchPlaceholder: string;
127
+ /** The filter chip list's name. @default 'Active filters' */
128
+ activeFilters: string;
129
+ /** A chip's remove button. `{column}` is replaced. @default 'Remove {column} filter' */
130
+ removeFilter: string;
131
+ /** The column manager button and its list. @default 'Columns' */
132
+ columns: string;
133
+ /** `{column}` is replaced. @default 'Move {column} up' */
134
+ moveUp: string;
135
+ /** `{column}` is replaced. @default 'Move {column} down' */
136
+ moveDown: string;
137
+ /** The column manager's addable-fields section. @default 'Add column' */
138
+ addColumnSection: string;
139
+ /** An addable field's button. `{column}` is replaced. @default 'Add {column}' */
140
+ addColumn: string;
141
+ /** The funnel button. `{column}` is replaced. @default 'Filter {column}' */
142
+ filterColumn: string;
143
+ /** The funnel button while a filter is set. `{column}` is replaced. @default 'Filter {column} (active)' */
144
+ filterColumnActive: string;
145
+ /** The text filter input. @default 'Filter value' */
146
+ filterValue: string;
147
+ /** The text filter placeholder when the column declares none. @default 'Contains…' */
148
+ filterPlaceholder: string;
149
+ /** The facet filter's checkbox group. @default 'Options' */
150
+ filterOptions: string;
151
+ /** @default 'From' */
152
+ from: string;
153
+ /** @default 'To' */
154
+ to: string;
155
+ /** @default 'Clear' */
156
+ clear: string;
157
+ /** @default 'Apply' */
158
+ apply: string;
159
+ /** A date-range chip with only a lower bound. `{date}` is replaced. @default 'from {date}' */
160
+ rangeFrom: string;
161
+ /** A date-range chip with only an upper bound. `{date}` is replaced. @default 'until {date}' */
162
+ rangeUntil: string;
163
+ /** The resize handle. `{column}` is replaced. @default 'Resize {column}' */
164
+ resizeColumn: string;
165
+ /** The inline edit input. `{column}` is replaced. @default 'Edit {column}' */
166
+ editColumn: string;
167
+ /** The default empty state's title. @default 'No results' */
168
+ noResults: string;
169
+ /** The default empty state's description. @default 'Try a different search or clear the filters.' */
170
+ noResultsDescription: string;
171
+ }
172
+ declare const defaultDataGridLabels: DataGridLabels;
173
+ interface DataGridCellEdit {
174
+ rowId: string;
175
+ columnId: string;
176
+ value: string;
177
+ }
178
+ interface DataGridBulkActionContext {
179
+ /** `true` when "Select all N" is on: act on every row matching the query, not only `selectedIds`. */
180
+ allMatching: boolean;
181
+ /** The rows matching the query (`rowCount`), the size of the set when `allMatching` is on. */
182
+ rowCount: number;
183
+ }
184
+ interface DataGridBulkAction {
185
+ id: string;
186
+ label: string;
187
+ variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost';
188
+ onAction: (selectedIds: string[], context: DataGridBulkActionContext) => void;
189
+ }
190
+ type DataGridDensity = 'compact' | 'comfortable';
191
+
192
+ export { DEFAULT_PAGE_SIZE as D, type DataGridAlign as a, type DataGridBulkAction as b, type DataGridBulkActionContext as c, type DataGridCellEdit as d, type DataGridColumnDef as e, type DataGridColumnExtras as f, type DataGridColumnMeta as g, type DataGridDateRange as h, type DataGridDateRangeFilter as i, type DataGridDensity as j, type DataGridFilter as k, type DataGridLabels as l, type DataGridSelectFilter as m, type DataGridState as n, type DataGridTextFilter as o, defaultDataGridLabels as p, defaultDataGridState as q, resolveDataGridState as r };
@@ -0,0 +1,73 @@
1
+ import { ColumnDef, PaginationState, SortingState, ColumnFiltersState, VisibilityState, ColumnOrderState, ColumnPinningState, RowSelectionState } from '@tanstack/react-table';
2
+
3
+ /**
4
+ * Everything the grid can change. The consumer owns it: every interaction
5
+ * calls `onStateChange` with the whole next state, and the grid renders
6
+ * whatever comes back (a server round-trip in between is the point).
7
+ */
8
+ interface DataGridState {
9
+ pagination: PaginationState;
10
+ sorting: SortingState;
11
+ columnFilters: ColumnFiltersState;
12
+ globalFilter: string;
13
+ columnVisibility: VisibilityState;
14
+ columnOrder: ColumnOrderState;
15
+ columnPinning: ColumnPinningState;
16
+ rowSelection: RowSelectionState;
17
+ }
18
+ declare const DEFAULT_PAGE_SIZE = 25;
19
+ declare const defaultDataGridState: DataGridState;
20
+ /** Fills the keys a consumer left out, so the grid always sees a full state. */
21
+ declare function resolveDataGridState(state: Partial<DataGridState> | undefined): DataGridState;
22
+ type DataGridAlign = 'start' | 'center' | 'end';
23
+ /** A text filter: one string, matched however the server matches it. */
24
+ interface DataGridTextFilter {
25
+ type: 'text';
26
+ placeholder?: string;
27
+ }
28
+ /** A facet filter: a list of options, of which any number may be picked. */
29
+ interface DataGridSelectFilter {
30
+ type: 'select';
31
+ options: readonly {
32
+ value: string;
33
+ label?: string;
34
+ }[];
35
+ }
36
+ /** A date range: ISO `YYYY-MM-DD` bounds, either side optional. */
37
+ interface DataGridDateRangeFilter {
38
+ type: 'date-range';
39
+ }
40
+ type DataGridFilter = DataGridTextFilter | DataGridSelectFilter | DataGridDateRangeFilter;
41
+ interface DataGridDateRange {
42
+ from?: string;
43
+ to?: string;
44
+ }
45
+ /** The ZUI extras on a TanStack column definition. */
46
+ interface DataGridColumnExtras {
47
+ /** Double-click or Enter on a cell turns it into an input; see `onCellEdit`. */
48
+ enableInlineEdit?: boolean;
49
+ /** Horizontal alignment of the head and the cells; `end` for numbers. */
50
+ align?: DataGridAlign;
51
+ /** Initial width in px (TanStack `size`); the user can resize from there. */
52
+ width?: number;
53
+ /** Declares the column's filter popover. */
54
+ filter?: DataGridFilter;
55
+ }
56
+ type DataGridColumnDef<TData, TValue = unknown> = ColumnDef<TData, TValue> & DataGridColumnExtras;
57
+ /** The extras may also be declared on `meta` (the TanStack way of extending a column). */
58
+ interface DataGridColumnMeta extends DataGridColumnExtras {
59
+ }
60
+ interface DataGridCellEdit {
61
+ rowId: string;
62
+ columnId: string;
63
+ value: string;
64
+ }
65
+ interface DataGridBulkAction {
66
+ id: string;
67
+ label: string;
68
+ variant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost';
69
+ onAction: (selectedIds: string[]) => void;
70
+ }
71
+ type DataGridDensity = 'compact' | 'comfortable';
72
+
73
+ export { type DataGridState as D, type DataGridDensity as a, type DataGridCellEdit as b, type DataGridBulkAction as c, DEFAULT_PAGE_SIZE as d, type DataGridAlign as e, type DataGridColumnDef as f, type DataGridColumnExtras as g, type DataGridColumnMeta as h, type DataGridDateRange as i, type DataGridDateRangeFilter as j, type DataGridFilter as k, type DataGridSelectFilter as l, type DataGridTextFilter as m, defaultDataGridState as n, resolveDataGridState as r };