@jielga/tmdatagrid 0.1.0 → 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.
- package/README.md +35 -2
- package/dist/index.d.ts +792 -327
- package/dist/index.js +1581 -892
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +15 -7
- package/skills/columns/SKILL.md +8 -7
- package/skills/features/SKILL.md +104 -16
- package/skills/getting-started/SKILL.md +78 -20
- package/skills/options/SKILL.md +12 -7
- package/skills/server-side/SKILL.md +5 -2
- package/src/tmdatagrid/TMDataGridContext.ts +1 -1
- package/src/tmdatagrid/components/TMDataGrid.module.css +73 -0
- package/src/tmdatagrid/{TMDataGrid.tsx → components/TMDataGrid.tsx} +15 -4
- package/src/tmdatagrid/components/TMDataGridColumnsPanel.module.css +25 -0
- package/src/tmdatagrid/{TMDataGridColumnsPanel.tsx → components/TMDataGridColumnsPanel.tsx} +10 -4
- package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +35 -0
- package/src/tmdatagrid/{TMDataGridFilterPanel.tsx → components/TMDataGridFilterPanel.tsx} +91 -14
- package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +35 -0
- package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +135 -0
- package/src/tmdatagrid/components/TMDataGridFooter.module.css +18 -0
- package/src/tmdatagrid/components/TMDataGridFooter.tsx +171 -0
- package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +48 -0
- package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +147 -0
- package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +159 -0
- package/src/tmdatagrid/{TMDataGridHeaderCell.tsx → components/TMDataGridHeaderCell.tsx} +99 -14
- package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +177 -0
- package/src/tmdatagrid/components/TMDataGridTable.module.css +137 -0
- package/src/tmdatagrid/components/TMDataGridTable.tsx +720 -0
- package/src/tmdatagrid/components/TMDataGridToolbar.module.css +12 -0
- package/src/tmdatagrid/{TMDataGridToolbar.tsx → components/TMDataGridToolbar.tsx} +8 -5
- package/src/tmdatagrid/{icons.ts → components/icons.ts} +5 -0
- package/src/tmdatagrid/components/sticky.module.css +45 -0
- package/src/tmdatagrid/core/capabilities.ts +215 -0
- package/src/tmdatagrid/{columnOrdering.ts → core/columnOrdering.ts} +2 -2
- package/src/tmdatagrid/{columnUtils.ts → core/columnUtils.ts} +1 -1
- package/src/tmdatagrid/{filterOperators.ts → core/filterOperators.ts} +25 -0
- package/src/tmdatagrid/core/grouping.ts +21 -0
- package/src/tmdatagrid/{persistence.ts → core/persistence.ts} +92 -2
- package/src/tmdatagrid/core/rowSelection.ts +202 -0
- package/src/tmdatagrid/index.ts +39 -9
- package/src/tmdatagrid/useTMDataGrid.tsx +318 -66
- package/src/tmdatagrid/TMDataGrid.module.css +0 -410
- package/src/tmdatagrid/TMDataGridFooter.tsx +0 -74
- package/src/tmdatagrid/TMDataGridTable.tsx +0 -297
- package/src/tmdatagrid/capabilities.ts +0 -117
- /package/src/tmdatagrid/{sizes.ts → core/sizes.ts} +0 -0
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/* Size scale. Row heights mirror SIZE_ROW_HEIGHT in sizes.ts — the virtualizer
|
|
2
|
-
needs the number in JS, so the two have to agree. */
|
|
3
|
-
.root[data-size="xs"] {
|
|
4
|
-
--dg-row-height: 34px;
|
|
5
|
-
--dg-header-height: 32px;
|
|
6
|
-
--dg-font-size: var(--mantine-font-size-xs);
|
|
7
|
-
--dg-padding: 6px;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.root[data-size="sm"] {
|
|
11
|
-
--dg-row-height: 42px;
|
|
12
|
-
--dg-header-height: 38px;
|
|
13
|
-
--dg-font-size: var(--mantine-font-size-sm);
|
|
14
|
-
--dg-padding: 8px;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.root[data-size="md"] {
|
|
18
|
-
--dg-row-height: 52px;
|
|
19
|
-
--dg-header-height: 44px;
|
|
20
|
-
--dg-font-size: var(--mantine-font-size-sm);
|
|
21
|
-
--dg-padding: 10px;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.root[data-size="lg"] {
|
|
25
|
-
--dg-row-height: 62px;
|
|
26
|
-
--dg-header-height: 52px;
|
|
27
|
-
--dg-font-size: var(--mantine-font-size-md);
|
|
28
|
-
--dg-padding: 14px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.root[data-size="xl"] {
|
|
32
|
-
--dg-row-height: 72px;
|
|
33
|
-
--dg-header-height: 60px;
|
|
34
|
-
--dg-font-size: var(--mantine-font-size-lg);
|
|
35
|
-
--dg-padding: 18px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.root {
|
|
39
|
-
/* Fallbacks, so the parts still work if rendered outside a sized root. */
|
|
40
|
-
--dg-row-height: 52px;
|
|
41
|
-
--dg-header-height: 44px;
|
|
42
|
-
--dg-font-size: var(--mantine-font-size-sm);
|
|
43
|
-
--dg-padding: 10px;
|
|
44
|
-
|
|
45
|
-
display: flex;
|
|
46
|
-
flex-direction: column;
|
|
47
|
-
min-height: 0;
|
|
48
|
-
overflow: hidden;
|
|
49
|
-
/* Header text is a stretched flex item, so an inherited `text-align: center`
|
|
50
|
-
from the host page would centre headers away from their cell content. */
|
|
51
|
-
text-align: left;
|
|
52
|
-
border: 1px solid var(--mantine-color-default-border);
|
|
53
|
-
border-radius: var(--mantine-radius-md);
|
|
54
|
-
background-color: var(--mantine-color-body);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.toolbar {
|
|
58
|
-
display: flex;
|
|
59
|
-
align-items: center;
|
|
60
|
-
gap: var(--mantine-spacing-xs);
|
|
61
|
-
padding: 6px var(--mantine-spacing-xs);
|
|
62
|
-
min-height: 42px;
|
|
63
|
-
flex-shrink: 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.toolbarSpacer {
|
|
67
|
-
flex: 1;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/* Anchors the filter panel, which floats over the first body rows. */
|
|
71
|
-
.tableWrapper {
|
|
72
|
-
position: relative;
|
|
73
|
-
flex: 1;
|
|
74
|
-
min-height: 0;
|
|
75
|
-
display: flex;
|
|
76
|
-
flex-direction: column;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.scrollContainer {
|
|
80
|
-
position: relative;
|
|
81
|
-
flex: 1;
|
|
82
|
-
min-height: 0;
|
|
83
|
-
overflow: auto;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* Column tracks are set inline via gridTemplateColumns. */
|
|
87
|
-
.grid {
|
|
88
|
-
display: grid;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* Rows are real layout boxes (not display: contents) so position: sticky works,
|
|
92
|
-
and subgrid keeps their cells on the parent's column tracks. */
|
|
93
|
-
.headerRow {
|
|
94
|
-
display: grid;
|
|
95
|
-
grid-column: 1 / -1;
|
|
96
|
-
grid-template-columns: subgrid;
|
|
97
|
-
position: sticky;
|
|
98
|
-
top: 0;
|
|
99
|
-
z-index: 3;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.headerCell {
|
|
103
|
-
position: relative;
|
|
104
|
-
display: flex;
|
|
105
|
-
align-items: center;
|
|
106
|
-
gap: 2px;
|
|
107
|
-
padding: 0 var(--dg-padding);
|
|
108
|
-
min-width: 0;
|
|
109
|
-
min-height: var(--dg-header-height);
|
|
110
|
-
font-weight: 600;
|
|
111
|
-
font-size: var(--dg-font-size);
|
|
112
|
-
background-color: var(--mantine-color-body);
|
|
113
|
-
border-bottom: 1px solid var(--mantine-color-default-border);
|
|
114
|
-
user-select: none;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.headerCell[data-align="right"] {
|
|
118
|
-
justify-content: flex-end;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.headerCell[data-align="center"] {
|
|
122
|
-
justify-content: center;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/* Sorted or filtered columns read as active, like the MUI data grid. */
|
|
126
|
-
.headerCell[data-active="true"] .headerTitle {
|
|
127
|
-
color: var(--mantine-primary-color-filled);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.headerTitle {
|
|
131
|
-
flex: 1 1 auto;
|
|
132
|
-
min-width: 0;
|
|
133
|
-
overflow: hidden;
|
|
134
|
-
text-overflow: ellipsis;
|
|
135
|
-
white-space: nowrap;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/* Right-aligned headers stay text so the ellipsis still works; centered ones
|
|
139
|
-
hold a control (the select-all checkbox), so they become a flex box. */
|
|
140
|
-
.headerCell[data-align="right"] .headerTitle {
|
|
141
|
-
text-align: right;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.headerCell[data-align="center"] .headerTitle {
|
|
145
|
-
display: flex;
|
|
146
|
-
justify-content: center;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.headerActions {
|
|
150
|
-
display: flex;
|
|
151
|
-
align-items: center;
|
|
152
|
-
gap: 0;
|
|
153
|
-
flex-shrink: 0;
|
|
154
|
-
margin-left: auto;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/* Actions always reserve their width. On right-aligned columns they move to the
|
|
158
|
-
leading edge so the header text stays flush with the cell values below it. */
|
|
159
|
-
.headerCell[data-align="right"] .headerActions {
|
|
160
|
-
order: -1;
|
|
161
|
-
margin-left: 0;
|
|
162
|
-
margin-right: auto;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/* Idle actions are removed from layout, not just faded — reserving their width
|
|
166
|
-
would truncate header text that otherwise fits. Indicators that must stay
|
|
167
|
-
visible (active sort, active filter, open menu) set data-pinned-visible. */
|
|
168
|
-
.headerAction {
|
|
169
|
-
display: none;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.headerCell:hover .headerAction,
|
|
173
|
-
.headerCell:focus-within .headerAction,
|
|
174
|
-
.headerAction[data-pinned-visible="true"] {
|
|
175
|
-
display: flex;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.headerCellSortable {
|
|
179
|
-
cursor: pointer;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/* Column reordering. The dragged header stays in place and dims — the browser
|
|
183
|
-
already carries a snapshot of it under the pointer — while the header being
|
|
184
|
-
dragged over draws a bar on the edge the column will land against. */
|
|
185
|
-
.headerCellDragging {
|
|
186
|
-
opacity: 0.4;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.headerCellDropBefore::before,
|
|
190
|
-
.headerCellDropAfter::before {
|
|
191
|
-
content: "";
|
|
192
|
-
position: absolute;
|
|
193
|
-
top: 0;
|
|
194
|
-
bottom: 0;
|
|
195
|
-
width: 2px;
|
|
196
|
-
background-color: var(--mantine-primary-color-filled);
|
|
197
|
-
z-index: 5;
|
|
198
|
-
pointer-events: none;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.headerCellDropBefore::before {
|
|
202
|
-
left: 0;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.headerCellDropAfter::before {
|
|
206
|
-
right: 0;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* Doubles as the column divider seen between every header cell. */
|
|
210
|
-
.columnSeparator {
|
|
211
|
-
position: absolute;
|
|
212
|
-
top: 25%;
|
|
213
|
-
right: 0;
|
|
214
|
-
height: 50%;
|
|
215
|
-
width: 10px;
|
|
216
|
-
transform: translateX(50%);
|
|
217
|
-
display: flex;
|
|
218
|
-
justify-content: center;
|
|
219
|
-
z-index: 1;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.columnSeparatorResizable {
|
|
223
|
-
cursor: col-resize;
|
|
224
|
-
touch-action: none;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/* The divider is a hover affordance, not permanent chrome — it only appears on
|
|
228
|
-
the header cell you are pointing at, or on the column being resized. */
|
|
229
|
-
.columnSeparator::after {
|
|
230
|
-
content: "";
|
|
231
|
-
width: 1px;
|
|
232
|
-
height: 100%;
|
|
233
|
-
background-color: transparent;
|
|
234
|
-
transition:
|
|
235
|
-
background-color 120ms ease,
|
|
236
|
-
width 120ms ease;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.headerCell:hover .columnSeparator::after,
|
|
240
|
-
.headerCell:focus-within .columnSeparator::after {
|
|
241
|
-
background-color: var(--mantine-color-default-border);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
.columnSeparatorResizable:hover::after,
|
|
245
|
-
.columnSeparatorActive::after {
|
|
246
|
-
width: 2px;
|
|
247
|
-
background-color: var(--mantine-primary-color-filled);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.bodyRow {
|
|
251
|
-
--row-bg: var(--mantine-color-body);
|
|
252
|
-
display: grid;
|
|
253
|
-
grid-column: 1 / -1;
|
|
254
|
-
grid-template-columns: subgrid;
|
|
255
|
-
align-items: stretch;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.bodyRow:hover {
|
|
259
|
-
--row-bg: var(--mantine-color-default-hover);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.bodyRow[data-selected="true"] {
|
|
263
|
-
--row-bg: var(--mantine-primary-color-light);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/* Clipping lives on .cellContent, not here — a pinned cell has to let its
|
|
267
|
-
boundary gradient escape past its own right/left edge. */
|
|
268
|
-
.bodyCell {
|
|
269
|
-
display: flex;
|
|
270
|
-
align-items: center;
|
|
271
|
-
padding: 0 var(--dg-padding);
|
|
272
|
-
border-bottom: 1px solid var(--mantine-color-default-border);
|
|
273
|
-
/* Inherited from .bodyRow — sticky cells need an opaque background. */
|
|
274
|
-
background-color: var(--row-bg);
|
|
275
|
-
font-size: var(--dg-font-size);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.cellContent {
|
|
279
|
-
min-width: 0;
|
|
280
|
-
overflow: hidden;
|
|
281
|
-
white-space: nowrap;
|
|
282
|
-
text-overflow: ellipsis;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
.bodyCell[data-align="right"] {
|
|
286
|
-
justify-content: flex-end;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.bodyCell[data-align="center"] {
|
|
290
|
-
justify-content: center;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/* Only stretch to fill when left-aligned, so right/centre stay put. */
|
|
294
|
-
.bodyCell[data-align="left"] .cellContent {
|
|
295
|
-
flex: 1 1 auto;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/* Boundary of a pinned column group.
|
|
299
|
-
A box-shadow is drawn per cell, and its blur fades in at each cell's own top
|
|
300
|
-
and bottom edge — stacked down a column that reads as banding at every row
|
|
301
|
-
seam. Instead: a crisp 1px border for the hard edge, plus a gradient pseudo
|
|
302
|
-
element pinned to `top: 0; bottom: 0` so consecutive cells butt together into
|
|
303
|
-
one unbroken band. Mantine sets `color-scheme` on the root, so light-dark()
|
|
304
|
-
resolves without a second selector. */
|
|
305
|
-
.stickyLeft {
|
|
306
|
-
border-right: 1px solid var(--mantine-color-default-border);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.stickyRight {
|
|
310
|
-
border-left: 1px solid var(--mantine-color-default-border);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
.stickyLeft::after,
|
|
314
|
-
.stickyRight::after {
|
|
315
|
-
content: "";
|
|
316
|
-
position: absolute;
|
|
317
|
-
top: 0;
|
|
318
|
-
bottom: 0;
|
|
319
|
-
width: 4px;
|
|
320
|
-
pointer-events: none;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.stickyLeft::after {
|
|
324
|
-
left: 100%;
|
|
325
|
-
background: linear-gradient(
|
|
326
|
-
to right,
|
|
327
|
-
light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.28)),
|
|
328
|
-
transparent
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.stickyRight::after {
|
|
333
|
-
right: 100%;
|
|
334
|
-
background: linear-gradient(
|
|
335
|
-
to left,
|
|
336
|
-
light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.28)),
|
|
337
|
-
transparent
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
.messageRow {
|
|
342
|
-
grid-column: 1 / -1;
|
|
343
|
-
display: flex;
|
|
344
|
-
flex-direction: column;
|
|
345
|
-
align-items: center;
|
|
346
|
-
justify-content: center;
|
|
347
|
-
gap: var(--mantine-spacing-xs);
|
|
348
|
-
padding: var(--mantine-spacing-xl);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
.footer {
|
|
352
|
-
display: flex;
|
|
353
|
-
align-items: center;
|
|
354
|
-
justify-content: flex-end;
|
|
355
|
-
gap: var(--mantine-spacing-lg);
|
|
356
|
-
padding: 4px var(--mantine-spacing-sm);
|
|
357
|
-
min-height: 48px;
|
|
358
|
-
flex-shrink: 0;
|
|
359
|
-
border-top: 1px solid var(--mantine-color-default-border);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.filterPanel {
|
|
363
|
-
position: absolute;
|
|
364
|
-
top: 46px;
|
|
365
|
-
left: var(--mantine-spacing-md);
|
|
366
|
-
z-index: 5;
|
|
367
|
-
padding: var(--mantine-spacing-sm);
|
|
368
|
-
border-radius: var(--mantine-radius-md);
|
|
369
|
-
border: 1px solid var(--mantine-color-default-border);
|
|
370
|
-
background-color: var(--mantine-color-body);
|
|
371
|
-
box-shadow: var(--mantine-shadow-md);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.filterRow {
|
|
375
|
-
display: flex;
|
|
376
|
-
align-items: flex-end;
|
|
377
|
-
gap: var(--mantine-spacing-xs);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/* Marks the pin position a column is currently in. */
|
|
381
|
-
.menuItemActive {
|
|
382
|
-
background-color: var(--mantine-color-default-hover);
|
|
383
|
-
font-weight: 600;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
.columnsPanel {
|
|
387
|
-
width: 280px;
|
|
388
|
-
display: flex;
|
|
389
|
-
flex-direction: column;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
.columnsPanelSearch {
|
|
393
|
-
padding: var(--mantine-spacing-sm);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
.columnsPanelList {
|
|
397
|
-
display: flex;
|
|
398
|
-
flex-direction: column;
|
|
399
|
-
gap: var(--mantine-spacing-sm);
|
|
400
|
-
padding: 0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
.columnsPanelFooter {
|
|
404
|
-
display: flex;
|
|
405
|
-
align-items: center;
|
|
406
|
-
justify-content: space-between;
|
|
407
|
-
gap: var(--mantine-spacing-sm);
|
|
408
|
-
padding: var(--mantine-spacing-sm);
|
|
409
|
-
border-top: 1px solid var(--mantine-color-default-border);
|
|
410
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { ActionIcon, Group, Select, Text } from "@mantine/core";
|
|
2
|
-
import { useSelector } from "@tanstack/react-store";
|
|
3
|
-
import classes from "./TMDataGrid.module.css";
|
|
4
|
-
import { useTMDataGridContext } from "./TMDataGridContext";
|
|
5
|
-
import { ChevronLeftIcon, ChevronRightIcon } from "./icons";
|
|
6
|
-
|
|
7
|
-
export type TMDataGridFooterProps = {
|
|
8
|
-
pageSizeOptions?: ReadonlyArray<number>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* MUI-style pager: "Rows per page · from–to of total · ‹ ›".
|
|
13
|
-
*
|
|
14
|
-
* Row totals come from `table.getRowCount()`, which prefers `options.rowCount`
|
|
15
|
-
* — so a server-paged grid shows the server's total without changes here.
|
|
16
|
-
*/
|
|
17
|
-
export function TMDataGridFooter({
|
|
18
|
-
pageSizeOptions = [10, 25, 50, 100],
|
|
19
|
-
}: TMDataGridFooterProps) {
|
|
20
|
-
const { table, controlSize } = useTMDataGridContext();
|
|
21
|
-
useSelector(table.store);
|
|
22
|
-
|
|
23
|
-
const { pageIndex, pageSize } = table.store.state.pagination;
|
|
24
|
-
const total = table.getRowCount();
|
|
25
|
-
const from = total === 0 ? 0 : pageIndex * pageSize + 1;
|
|
26
|
-
const to = Math.min(total, (pageIndex + 1) * pageSize);
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div className={classes.footer}>
|
|
30
|
-
<Group gap="xs" wrap="nowrap">
|
|
31
|
-
<Text size={controlSize} c="dimmed">
|
|
32
|
-
Rows per page:
|
|
33
|
-
</Text>
|
|
34
|
-
<Select
|
|
35
|
-
size={controlSize}
|
|
36
|
-
w={78}
|
|
37
|
-
allowDeselect={false}
|
|
38
|
-
variant="unstyled"
|
|
39
|
-
data={pageSizeOptions.map(String)}
|
|
40
|
-
value={String(pageSize)}
|
|
41
|
-
onChange={(value) => {
|
|
42
|
-
table.setPageSize(Number(value) || pageSizeOptions[0]);
|
|
43
|
-
table.setPageIndex(0);
|
|
44
|
-
}}
|
|
45
|
-
/>
|
|
46
|
-
</Group>
|
|
47
|
-
|
|
48
|
-
<Text size={controlSize} c="dimmed">
|
|
49
|
-
{from}–{to} of {total}
|
|
50
|
-
</Text>
|
|
51
|
-
|
|
52
|
-
<Group gap={4} wrap="nowrap">
|
|
53
|
-
<ActionIcon
|
|
54
|
-
variant="subtle"
|
|
55
|
-
color="gray"
|
|
56
|
-
aria-label="Previous page"
|
|
57
|
-
disabled={!table.getCanPreviousPage()}
|
|
58
|
-
onClick={() => table.previousPage()}
|
|
59
|
-
>
|
|
60
|
-
<ChevronLeftIcon size={18} stroke={1.6} />
|
|
61
|
-
</ActionIcon>
|
|
62
|
-
<ActionIcon
|
|
63
|
-
variant="subtle"
|
|
64
|
-
color="gray"
|
|
65
|
-
aria-label="Next page"
|
|
66
|
-
disabled={!table.getCanNextPage()}
|
|
67
|
-
onClick={() => table.nextPage()}
|
|
68
|
-
>
|
|
69
|
-
<ChevronRightIcon size={18} stroke={1.6} />
|
|
70
|
-
</ActionIcon>
|
|
71
|
-
</Group>
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
}
|