@jielga/tmdatagrid 1.0.2 → 1.1.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 +17 -14
- package/dist/index.d.ts +172 -16
- package/dist/index.js +1691 -1599
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/appearance/SKILL.md +1 -1
- package/skills/cell-selection/SKILL.md +4 -4
- package/skills/columns/SKILL.md +1 -1
- package/skills/data/SKILL.md +33 -20
- package/skills/editing/SKILL.md +82 -75
- package/skills/editing/references/editing-api.md +1 -1
- package/skills/filtering/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +23 -17
- package/skills/grouping/SKILL.md +1 -1
- package/skills/options/SKILL.md +1 -1
- package/skills/rows/SKILL.md +41 -11
- package/skills/rows/references/rows-api.md +3 -2
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +1 -1
- package/src/tmdatagrid/components/TMDataGridEditActions.tsx +132 -32
- package/src/tmdatagrid/components/TMDataGridFooter.tsx +223 -95
- package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +41 -4
- package/src/tmdatagrid/components/TMDataGridTable.tsx +102 -44
- package/src/tmdatagrid/index.ts +17 -2
|
@@ -24,7 +24,10 @@ import classes from "./TMDataGridTable.module.css";
|
|
|
24
24
|
import sticky from "./sticky.module.css";
|
|
25
25
|
import { type TMDataGridRowData, useTMDataGridContext } from "../TMDataGridContext";
|
|
26
26
|
import { TMDataGridFilterPanel } from "./TMDataGridFilterPanel";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
TMDataGridHeaderCell,
|
|
29
|
+
type TMDataGridColumnMenuItemsRenderer,
|
|
30
|
+
} from "./TMDataGridHeaderCell";
|
|
28
31
|
import {
|
|
29
32
|
TMDataGridCellEditor,
|
|
30
33
|
type TMDataGridCellEditorClose,
|
|
@@ -386,7 +389,7 @@ function TMDataGridBodyCell({
|
|
|
386
389
|
|
|
387
390
|
/**
|
|
388
391
|
* The virtualized body rows, wrapped in the single Menu that serves all of them
|
|
389
|
-
* when `
|
|
392
|
+
* when `renderRowContextMenu` is set.
|
|
390
393
|
*
|
|
391
394
|
* One instance for the whole body rather than one per row. A Mantine `Menu` is
|
|
392
395
|
* a `Popover`, and a closed Popover still runs its hooks on every render - and
|
|
@@ -447,7 +450,7 @@ function TMDataGridBodyRowGroup({
|
|
|
447
450
|
);
|
|
448
451
|
}
|
|
449
452
|
|
|
450
|
-
/** What
|
|
453
|
+
/** What `renderRowContextMenu` is handed for the right-clicked row. */
|
|
451
454
|
export type TMDataGridRowContextMenuArgs<TData extends RowData> = {
|
|
452
455
|
table: Table<TMDataGridFeatures, TData>;
|
|
453
456
|
row: Row<TMDataGridFeatures, TData>;
|
|
@@ -462,6 +465,14 @@ export type TMDataGridRowContextMenuArgs<TData extends RowData> = {
|
|
|
462
465
|
* `closeOnItemClick`), so this is for content that isn't a menu item.
|
|
463
466
|
*/
|
|
464
467
|
close: () => void;
|
|
468
|
+
/**
|
|
469
|
+
* The grid's own items for this menu: the cell copy and export items, under
|
|
470
|
+
* `cellSelection: "range"`, and `null` otherwise.
|
|
471
|
+
*
|
|
472
|
+
* Placing it decides the order. Ignore it and the grid keeps today's
|
|
473
|
+
* behavior, rendering its items above a divider and yours below.
|
|
474
|
+
*/
|
|
475
|
+
internalItems: ReactNode;
|
|
465
476
|
};
|
|
466
477
|
|
|
467
478
|
/**
|
|
@@ -469,7 +480,7 @@ export type TMDataGridRowContextMenuArgs<TData extends RowData> = {
|
|
|
469
480
|
* `Menu.Divider`, `Menu.Sub`, or any other node. The grid owns the `Menu` and
|
|
470
481
|
* its `Menu.Dropdown`; this fills the dropdown.
|
|
471
482
|
*/
|
|
472
|
-
export type
|
|
483
|
+
export type TMDataGridRowContextMenuRenderer<TData extends RowData> = (
|
|
473
484
|
args: TMDataGridRowContextMenuArgs<TData>,
|
|
474
485
|
) => ReactNode;
|
|
475
486
|
|
|
@@ -509,7 +520,7 @@ export type TMDataGridTableProps<TData extends RowData> = {
|
|
|
509
520
|
/** As {@link onCellClick}; a double-click that opens an editor still does. */
|
|
510
521
|
onCellDoubleClick?: (args: TMDataGridCellEventArgs<TData>) => void;
|
|
511
522
|
/**
|
|
512
|
-
* As {@link onCellClick}; `
|
|
523
|
+
* As {@link onCellClick}; `renderRowContextMenu` and the cell-selection menu still
|
|
513
524
|
* open. To suppress the browser's own menu on a grid with neither, call
|
|
514
525
|
* `event.preventDefault()` here.
|
|
515
526
|
*/
|
|
@@ -575,7 +586,7 @@ export type TMDataGridTableProps<TData extends RowData> = {
|
|
|
575
586
|
*
|
|
576
587
|
* ```tsx
|
|
577
588
|
* <TMDataGrid.Table<Employee>
|
|
578
|
-
*
|
|
589
|
+
* renderRowContextMenu={({ row, close }) => (
|
|
579
590
|
* <>
|
|
580
591
|
* <Menu.Label>{row.original.firstName}</Menu.Label>
|
|
581
592
|
* <Menu.Item onClick={() => open(row.original.id)}>Open</Menu.Item>
|
|
@@ -588,10 +599,33 @@ export type TMDataGridTableProps<TData extends RowData> = {
|
|
|
588
599
|
* />
|
|
589
600
|
* ```
|
|
590
601
|
*
|
|
602
|
+
* `internalItems` is the grid's own half - place it to control the order,
|
|
603
|
+
* ignore it and the grid keeps its items above a divider and yours below.
|
|
604
|
+
*
|
|
591
605
|
* Called during render, and only for the row whose menu is open - so it stays
|
|
592
606
|
* a pure function of the row, and cost per row does not matter.
|
|
593
607
|
*/
|
|
594
|
-
|
|
608
|
+
renderRowContextMenu?: TMDataGridRowContextMenuRenderer<TData>;
|
|
609
|
+
/**
|
|
610
|
+
* Replaces a column menu's contents, taking the grid's own items and
|
|
611
|
+
* returning the full list.
|
|
612
|
+
*
|
|
613
|
+
* ```tsx
|
|
614
|
+
* <TMDataGrid.Table
|
|
615
|
+
* renderColumnMenuItems={({ column, internalItems }) => [
|
|
616
|
+
* ...internalItems,
|
|
617
|
+
* <Menu.Divider key="custom" />,
|
|
618
|
+
* <Menu.Item key="stats" onClick={() => showStats(column.id)}>
|
|
619
|
+
* Statistics
|
|
620
|
+
* </Menu.Item>,
|
|
621
|
+
* ]}
|
|
622
|
+
* />
|
|
623
|
+
* ```
|
|
624
|
+
*
|
|
625
|
+
* Returning an empty list leaves the column with no menu button, the same as
|
|
626
|
+
* a column whose every feature is switched off.
|
|
627
|
+
*/
|
|
628
|
+
renderColumnMenuItems?: TMDataGridColumnMenuItemsRenderer;
|
|
595
629
|
/**
|
|
596
630
|
* Passed to the Mantine `Menu` the grid wraps the row in - `width`, `shadow`,
|
|
597
631
|
* `position`, `transitionProps` and the rest. Its open state is the grid's.
|
|
@@ -651,7 +685,8 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
651
685
|
onScrollToLeft,
|
|
652
686
|
onScrollToRight,
|
|
653
687
|
renderEmptyState,
|
|
654
|
-
|
|
688
|
+
renderRowContextMenu,
|
|
689
|
+
renderColumnMenuItems,
|
|
655
690
|
rowContextMenuProps,
|
|
656
691
|
cellExport,
|
|
657
692
|
onReachEnd,
|
|
@@ -1714,29 +1749,13 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
1714
1749
|
? undefined
|
|
1715
1750
|
: rows.find((row) => row.id === contextMenuTarget.rowId);
|
|
1716
1751
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
*/
|
|
1725
|
-
const rowMenuContent =
|
|
1726
|
-
rowContextMenu &&
|
|
1727
|
-
contextMenuTarget &&
|
|
1728
|
-
contextMenuRow &&
|
|
1729
|
-
!contextMenuRow.getIsGrouped()
|
|
1730
|
-
? rowContextMenu({
|
|
1731
|
-
table: table as unknown as Table<TMDataGridFeatures, TData>,
|
|
1732
|
-
row: contextMenuRow as unknown as Row<TMDataGridFeatures, TData>,
|
|
1733
|
-
cell: (contextMenuRow
|
|
1734
|
-
.getAllCells()
|
|
1735
|
-
.find((cell) => cell.column.id === contextMenuTarget.columnId) ??
|
|
1736
|
-
null) as unknown as Cell<TMDataGridFeatures, TData, unknown> | null,
|
|
1737
|
-
close: closeContextMenu,
|
|
1738
|
-
}) ?? null
|
|
1739
|
-
: null;
|
|
1752
|
+
const canRenderRowMenu =
|
|
1753
|
+
renderRowContextMenu !== undefined &&
|
|
1754
|
+
contextMenuTarget !== null &&
|
|
1755
|
+
contextMenuRow !== undefined &&
|
|
1756
|
+
!contextMenuRow.getIsGrouped();
|
|
1757
|
+
|
|
1758
|
+
|
|
1740
1759
|
|
|
1741
1760
|
/**
|
|
1742
1761
|
* The built-in half of the menu: what to do with the cells that are selected.
|
|
@@ -1780,18 +1799,56 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
1780
1799
|
</>
|
|
1781
1800
|
) : null;
|
|
1782
1801
|
|
|
1802
|
+
/**
|
|
1803
|
+
* The consumer's half, built for the open row only - so the render prop runs
|
|
1804
|
+
* once per opened menu rather than once per mounted row. `null` back from it
|
|
1805
|
+
* means this row has no menu, which is also how the menu stays shut.
|
|
1806
|
+
*
|
|
1807
|
+
* `internalItems` is a getter, and reading it is the signal: a consumer who
|
|
1808
|
+
* touches it has taken the composition over, so the grid stops prepending
|
|
1809
|
+
* its own half. One who never mentions it gets today's behavior, the cell
|
|
1810
|
+
* items above a divider. The alternative - a second prop declaring intent -
|
|
1811
|
+
* asks people to say twice what the placement already says.
|
|
1812
|
+
*
|
|
1813
|
+
* The casts put back the concrete row type the context boundary erased - the
|
|
1814
|
+
* same crossing `onRowClick` makes.
|
|
1815
|
+
*/
|
|
1816
|
+
let tookOverMenu = false;
|
|
1817
|
+
const rowMenuContent = canRenderRowMenu
|
|
1818
|
+
? (renderRowContextMenu({
|
|
1819
|
+
table: table as unknown as Table<TMDataGridFeatures, TData>,
|
|
1820
|
+
row: contextMenuRow as unknown as Row<TMDataGridFeatures, TData>,
|
|
1821
|
+
cell: (contextMenuRow
|
|
1822
|
+
?.getAllCells()
|
|
1823
|
+
.find((cell) => cell.column.id === contextMenuTarget?.columnId) ??
|
|
1824
|
+
null) as unknown as Cell<TMDataGridFeatures, TData, unknown> | null,
|
|
1825
|
+
close: closeContextMenu,
|
|
1826
|
+
get internalItems() {
|
|
1827
|
+
tookOverMenu = true;
|
|
1828
|
+
return cellMenuContent;
|
|
1829
|
+
},
|
|
1830
|
+
}) ?? null)
|
|
1831
|
+
: null;
|
|
1832
|
+
|
|
1783
1833
|
/**
|
|
1784
1834
|
* The two halves, in the order they are about: the cells first, since the
|
|
1785
1835
|
* right-click landed on one, then whatever the consumer offers for the row.
|
|
1836
|
+
* Unless the consumer took the composition over, in which case what they
|
|
1837
|
+
* returned is the whole menu.
|
|
1786
1838
|
*/
|
|
1787
|
-
const contextMenuContent =
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1839
|
+
const contextMenuContent = tookOverMenu
|
|
1840
|
+
? rowMenuContent
|
|
1841
|
+
: cellMenuContent === null && rowMenuContent === null
|
|
1842
|
+
? null
|
|
1843
|
+
: (
|
|
1844
|
+
<>
|
|
1845
|
+
{cellMenuContent}
|
|
1846
|
+
{cellMenuContent !== null && rowMenuContent !== null && (
|
|
1847
|
+
<Menu.Divider />
|
|
1848
|
+
)}
|
|
1849
|
+
{rowMenuContent}
|
|
1850
|
+
</>
|
|
1851
|
+
);
|
|
1795
1852
|
|
|
1796
1853
|
/**
|
|
1797
1854
|
* Which edges the scroll position is currently at. Seeded "at top-left",
|
|
@@ -1908,6 +1965,7 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
1908
1965
|
>
|
|
1909
1966
|
{headerGroup.headers.map((header) => (
|
|
1910
1967
|
<TMDataGridHeaderCell
|
|
1968
|
+
renderColumnMenuItems={renderColumnMenuItems}
|
|
1911
1969
|
key={header.id}
|
|
1912
1970
|
header={header}
|
|
1913
1971
|
layout={layoutFor(header.column.id)}
|
|
@@ -1929,8 +1987,8 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
1929
1987
|
|
|
1930
1988
|
<TMDataGridBodyRowGroup
|
|
1931
1989
|
// Under `"range"` the grid has a menu of its own to offer, so the
|
|
1932
|
-
// wrapper goes on even without a consumer's `
|
|
1933
|
-
enabled={
|
|
1990
|
+
// wrapper goes on even without a consumer's `renderRowContextMenu`.
|
|
1991
|
+
enabled={renderRowContextMenu !== undefined || cellRangeSelection}
|
|
1934
1992
|
menuContent={contextMenuContent}
|
|
1935
1993
|
menuProps={rowContextMenuProps}
|
|
1936
1994
|
onContextMenu={handleContextMenu}
|
|
@@ -2110,14 +2168,14 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
2110
2168
|
// is recorded before the dropdown is built.
|
|
2111
2169
|
//
|
|
2112
2170
|
// A group row records itself only for the cell menu, which is
|
|
2113
|
-
// about the cells it covers. `
|
|
2171
|
+
// about the cells it covers. `renderRowContextMenu` is still never
|
|
2114
2172
|
// called for one: TanStack builds a group row on its first
|
|
2115
2173
|
// child's record, so a render prop reaching for `row.original`
|
|
2116
2174
|
// would be handed a real employee that has nothing to do with
|
|
2117
2175
|
// the group - see where the content is built. The browser menu
|
|
2118
2176
|
// stays suppressed over them either way.
|
|
2119
2177
|
onContextMenu={
|
|
2120
|
-
(
|
|
2178
|
+
(renderRowContextMenu && !isGroupRow) || cellRangeSelection
|
|
2121
2179
|
? () => {
|
|
2122
2180
|
contextMenuRowRef.current = row.id;
|
|
2123
2181
|
}
|
|
@@ -2252,7 +2310,7 @@ export function TMDataGridTable<TData extends RowData = TMDataGridRowData>({
|
|
|
2252
2310
|
: undefined
|
|
2253
2311
|
}
|
|
2254
2312
|
onContextMenu={
|
|
2255
|
-
|
|
2313
|
+
renderRowContextMenu || cellRangeSelection || onCellContextMenu
|
|
2256
2314
|
? (event) => {
|
|
2257
2315
|
contextMenuColumnRef.current = cell.column.id;
|
|
2258
2316
|
if (isGroupRow) return;
|
package/src/tmdatagrid/index.ts
CHANGED
|
@@ -66,7 +66,14 @@ export {
|
|
|
66
66
|
type TMDataGridOptionsArgs,
|
|
67
67
|
type TMDataGridOptionsSource,
|
|
68
68
|
} from "./core/columnOptions";
|
|
69
|
-
export {
|
|
69
|
+
export {
|
|
70
|
+
TMDataGridEditActions,
|
|
71
|
+
type TMDataGridEditActionsActions,
|
|
72
|
+
type TMDataGridEditActionsControls,
|
|
73
|
+
type TMDataGridEditActionsProps,
|
|
74
|
+
type TMDataGridEditActionsSlotArgs,
|
|
75
|
+
type TMDataGridEditActionsState,
|
|
76
|
+
} from "./components/TMDataGridEditActions";
|
|
70
77
|
export {
|
|
71
78
|
clearedValueForType,
|
|
72
79
|
getEditFieldName,
|
|
@@ -207,13 +214,21 @@ export type {
|
|
|
207
214
|
TMDataGridCellEventArgs,
|
|
208
215
|
TMDataGridCellNav,
|
|
209
216
|
TMDataGridColumnLayout,
|
|
210
|
-
TMDataGridRowContextMenu,
|
|
211
217
|
TMDataGridRowContextMenuArgs,
|
|
218
|
+
TMDataGridRowContextMenuRenderer,
|
|
212
219
|
TMDataGridRowStyle,
|
|
213
220
|
TMDataGridTableProps,
|
|
214
221
|
} from "./components/TMDataGridTable";
|
|
222
|
+
export type {
|
|
223
|
+
TMDataGridColumnMenuItemsArgs,
|
|
224
|
+
TMDataGridColumnMenuItemsRenderer,
|
|
225
|
+
} from "./components/TMDataGridHeaderCell";
|
|
215
226
|
export {
|
|
216
227
|
getTMDataGridPaginationApi,
|
|
217
228
|
type TMDataGridFooterProps,
|
|
229
|
+
type TMDataGridPaginationActions,
|
|
218
230
|
type TMDataGridPaginationApi,
|
|
231
|
+
type TMDataGridPaginationControls,
|
|
232
|
+
type TMDataGridPaginationSlotArgs,
|
|
233
|
+
type TMDataGridPaginationState,
|
|
219
234
|
} from "./components/TMDataGridFooter";
|