material-react-table 0.23.5 → 0.24.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/dist/utils.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare const getAllLeafColumnDefs: <TData extends Record<string, any> =
4
4
  export declare const prepareColumns: <TData extends Record<string, any> = {}>(columnDefs: MRT_ColumnDef<TData>[], currentFilterFns: {
5
5
  [key: string]: "between" | "contains" | "empty" | "endsWith" | "equals" | "fuzzy" | "greaterThan" | "lessThan" | "notEmpty" | "notEquals" | "startsWith" | "includesString" | "includesStringSensitive" | "equalsString" | "arrIncludes" | "arrIncludesAll" | "arrIncludesSome" | "weakEquals" | "inNumberRange";
6
6
  }) => MRT_DefinedColumnDef<TData>[];
7
- export declare const reorderColumn: <TData extends Record<string, any> = {}>(movingColumn: MRT_Column<TData>, receivingColumn: MRT_Column<TData>, columnOrder: ColumnOrderState) => ColumnOrderState;
7
+ export declare const reorderColumn: <TData extends Record<string, any> = {}>(draggedColumn: MRT_Column<TData>, targetColumn: MRT_Column<TData>, columnOrder: ColumnOrderState) => ColumnOrderState;
8
8
  export declare const getLeadingDisplayColumnIds: <TData extends Record<string, any> = {}>(props: MaterialReactTableProps<TData>) => string[];
9
9
  export declare const getTrailingDisplayColumnIds: <TData extends Record<string, any> = {}>(props: MaterialReactTableProps<TData>) => (string | false | undefined)[];
10
10
  export declare const getDefaultColumnOrderIds: <TData extends Record<string, any> = {}>(props: MaterialReactTableProps<TData>) => string[];
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.23.5",
2
+ "version": "0.24.0",
3
3
  "license": "MIT",
4
4
  "name": "material-react-table",
5
5
  "description": "A fully featured Material UI implementation of TanStack React Table, inspired by material-table and the MUI X DataGrid, written from the ground up in TypeScript.",
@@ -1,12 +1,13 @@
1
1
  import React, {
2
2
  ChangeEvent,
3
3
  Dispatch,
4
+ DragEvent,
4
5
  FC,
5
6
  FocusEvent,
6
7
  ReactNode,
7
8
  SetStateAction,
8
9
  } from 'react';
9
- import {
10
+ import type {
10
11
  AlertProps,
11
12
  ButtonProps,
12
13
  CheckboxProps,
@@ -25,7 +26,7 @@ import {
25
26
  TextFieldProps,
26
27
  ToolbarProps,
27
28
  } from '@mui/material';
28
- import {
29
+ import type {
29
30
  Cell,
30
31
  Column,
31
32
  ColumnDef,
@@ -39,7 +40,7 @@ import {
39
40
  TableOptions,
40
41
  TableState,
41
42
  } from '@tanstack/react-table';
42
- import { Options as VirtualizerOptions } from 'react-virtual';
43
+ import type { Options as VirtualizerOptions } from 'react-virtual';
43
44
  import { MRT_Localization, MRT_DefaultLocalization_EN } from './localization';
44
45
  import { MRT_Default_Icons, MRT_Icons } from './icons';
45
46
  import { MRT_TableRoot } from './table/MRT_TableRoot';
@@ -107,6 +108,7 @@ export type MRT_TableInstance<TData extends Record<string, any> = {}> = Omit<
107
108
  localization: MRT_Localization;
108
109
  };
109
110
  setCurrentDraggingColumn: Dispatch<SetStateAction<MRT_Column<TData> | null>>;
111
+ setCurrentDraggingRow: Dispatch<SetStateAction<MRT_Row<TData> | null>>;
110
112
  setCurrentEditingCell: Dispatch<SetStateAction<MRT_Cell | null>>;
111
113
  setCurrentEditingRow: Dispatch<SetStateAction<MRT_Row | null>>;
112
114
  setCurrentFilterFns: Dispatch<
@@ -116,6 +118,7 @@ export type MRT_TableInstance<TData extends Record<string, any> = {}> = Omit<
116
118
  >;
117
119
  setCurrentGlobalFilterFn: Dispatch<SetStateAction<MRT_FilterOption>>;
118
120
  setCurrentHoveredColumn: Dispatch<SetStateAction<MRT_Column<TData> | null>>;
121
+ setCurrentHoveredRow: Dispatch<SetStateAction<MRT_Row | null>>;
119
122
  setDensity: Dispatch<SetStateAction<'comfortable' | 'compact' | 'spacious'>>;
120
123
  setIsFullScreen: Dispatch<SetStateAction<boolean>>;
121
124
  setShowAlertBanner: Dispatch<SetStateAction<boolean>>;
@@ -126,11 +129,13 @@ export type MRT_TableInstance<TData extends Record<string, any> = {}> = Omit<
126
129
  export type MRT_TableState<TData extends Record<string, any> = {}> =
127
130
  TableState & {
128
131
  currentDraggingColumn: MRT_Column<TData> | null;
132
+ currentDraggingRow: MRT_Row<TData> | null;
129
133
  currentEditingCell: MRT_Cell<TData> | null;
130
134
  currentEditingRow: MRT_Row<TData> | null;
131
135
  currentFilterFns: Record<string, MRT_FilterOption>;
132
136
  currentGlobalFilterFn: Record<string, MRT_FilterOption>;
133
137
  currentHoveredColumn: MRT_Column<TData> | null;
138
+ currentHoveredRow: MRT_Row<TData> | null;
134
139
  density: 'comfortable' | 'compact' | 'spacious';
135
140
  isFullScreen: boolean;
136
141
  isLoading: boolean;
@@ -226,6 +231,7 @@ export type MRT_ColumnDef<TData extends Record<string, any> = {}> = Omit<
226
231
  columns?: MRT_ColumnDef<TData>[];
227
232
  enableClickToCopy?: boolean;
228
233
  enableColumnActions?: boolean;
234
+ enableColumnDragging?: boolean;
229
235
  enableColumnFilterChangeMode?: boolean;
230
236
  enableColumnOrdering?: boolean;
231
237
  enableEditing?: boolean;
@@ -295,6 +301,15 @@ export type MRT_ColumnDef<TData extends Record<string, any> = {}> = Omit<
295
301
  table: MRT_TableInstance<TData>;
296
302
  column: MRT_Column<TData>;
297
303
  }) => IconButtonProps);
304
+ muiTableHeadCellDragHandleProps?:
305
+ | IconButtonProps
306
+ | (({
307
+ table,
308
+ column,
309
+ }: {
310
+ table: MRT_TableInstance<TData>;
311
+ column: MRT_Column<TData>;
312
+ }) => IconButtonProps);
298
313
  muiTableHeadCellFilterTextFieldProps?:
299
314
  | TextFieldProps
300
315
  | (({
@@ -368,12 +383,11 @@ export type MRT_HeaderGroup<TData extends Record<string, any> = {}> = Omit<
368
383
 
369
384
  export type MRT_Row<TData extends Record<string, any> = {}> = Omit<
370
385
  Row<TData>,
371
- 'getVisibleCells' | 'getAllCells' | 'subRows' | 'original' | '_valuesCache'
386
+ 'getVisibleCells' | 'getAllCells' | 'subRows' | '_valuesCache'
372
387
  > & {
373
388
  getAllCells: () => MRT_Cell<TData>[];
374
389
  getVisibleCells: () => MRT_Cell<TData>[];
375
390
  subRows?: MRT_Row<TData>[];
376
- original: TData;
377
391
  _valuesCache?: TData;
378
392
  };
379
393
 
@@ -397,11 +411,21 @@ export type MRT_FilterFn<TData extends Record<string, any> = {}> =
397
411
  | FilterFn<TData>
398
412
  | MRT_FilterOption;
399
413
 
414
+ /**
415
+ * `columns` and `data` props are the only required props, but there are over 150 other optional props.
416
+ *
417
+ * See more info on creating columns and data on the official docs site:
418
+ * @link https://www.material-react-table.com/docs/usage
419
+ *
420
+ * See the full props list on the official docs site:
421
+ * @link https://www.material-react-table.com/docs/api/props
422
+ */
400
423
  export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
401
424
  MRT_TableOptions<TData> & {
402
425
  editingMode?: 'table' | 'row' | 'cell';
403
426
  enableClickToCopy?: boolean;
404
427
  enableColumnActions?: boolean;
428
+ enableColumnDragging?: boolean;
405
429
  enableColumnFilterChangeMode?: boolean;
406
430
  enableColumnOrdering?: boolean;
407
431
  enableDensityToggle?: boolean;
@@ -412,7 +436,9 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
412
436
  enableGlobalFilterRankedResults?: boolean;
413
437
  enablePagination?: boolean;
414
438
  enableRowActions?: boolean;
439
+ enableRowDragging?: boolean;
415
440
  enableRowNumbers?: boolean;
441
+ enableRowOrdering?: boolean;
416
442
  enableRowVirtualization?: boolean;
417
443
  enableSelectAll?: boolean;
418
444
  enableStickyHeader?: boolean;
@@ -496,6 +522,15 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
496
522
  table: MRT_TableInstance<TData>;
497
523
  cell: MRT_Cell<TData>;
498
524
  }) => SkeletonProps);
525
+ muiTableBodyRowDragHandleProps?:
526
+ | IconButtonProps
527
+ | (({
528
+ table,
529
+ row,
530
+ }: {
531
+ table: MRT_TableInstance<TData>;
532
+ row: MRT_Row<TData>;
533
+ }) => IconButtonProps);
499
534
  muiTableBodyProps?:
500
535
  | TableBodyProps
501
536
  | (({ table }: { table: MRT_TableInstance<TData> }) => TableBodyProps);
@@ -554,6 +589,15 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
554
589
  table: MRT_TableInstance<TData>;
555
590
  column: MRT_Column<TData>;
556
591
  }) => IconButtonProps);
592
+ muiTableHeadCellDragHandleProps?:
593
+ | IconButtonProps
594
+ | (({
595
+ table,
596
+ column,
597
+ }: {
598
+ table: MRT_TableInstance<TData>;
599
+ column: MRT_Column<TData>;
600
+ }) => IconButtonProps);
557
601
  muiTableHeadCellFilterTextFieldProps?:
558
602
  | TextFieldProps
559
603
  | (({
@@ -624,12 +668,23 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
624
668
  cell: MRT_Cell<TData>;
625
669
  table: MRT_TableInstance<TData>;
626
670
  }) => void;
671
+ onColumnDrop?: ({
672
+ event,
673
+ draggedColumn,
674
+ targetColumn,
675
+ }: {
676
+ event: DragEvent<HTMLButtonElement>;
677
+ draggedColumn: MRT_Column<TData>;
678
+ targetColumn: MRT_Column<TData> | null;
679
+ }) => void;
627
680
  onCurrentDraggingColumnChange?: OnChangeFn<MRT_Column<TData> | null>;
681
+ onCurrentDraggingRowChange?: OnChangeFn<MRT_Row<TData> | null>;
628
682
  onCurrentEditingCellChange?: OnChangeFn<MRT_Cell<TData> | null>;
629
683
  onCurrentEditingRowChange?: OnChangeFn<MRT_Row<TData> | null>;
630
684
  onCurrentFilterFnsChange?: OnChangeFn<{ [key: string]: MRT_FilterOption }>;
631
685
  onCurrentGlobalFilterFnChange?: OnChangeFn<MRT_FilterOption>;
632
686
  onCurrentHoveredColumnChange?: OnChangeFn<MRT_Column<TData> | null>;
687
+ onCurrentHoveredRowChange?: OnChangeFn<MRT_Row<TData> | null>;
633
688
  onEditRowSubmit?: ({
634
689
  row,
635
690
  table,
@@ -639,6 +694,15 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
639
694
  }) => Promise<void> | void;
640
695
  onDensityChange?: OnChangeFn<boolean>;
641
696
  onIsFullScreenChange?: OnChangeFn<boolean>;
697
+ onRowDrop?: ({
698
+ event,
699
+ draggedRow,
700
+ targetRow,
701
+ }: {
702
+ event: DragEvent<HTMLButtonElement>;
703
+ draggedRow: MRT_Row<TData>;
704
+ targetRow: MRT_Row<TData> | null;
705
+ }) => void;
642
706
  onShowAlertBannerChange?: OnChangeFn<boolean>;
643
707
  onShowFiltersChange?: OnChangeFn<boolean>;
644
708
  onShowGlobalFilterChange?: OnChangeFn<boolean>;
@@ -711,15 +775,6 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
711
775
  virtualizerProps?: Partial<VirtualizerOptions<HTMLDivElement>>;
712
776
  };
713
777
 
714
- /**
715
- * `columns` and `data` props are the only required props, but there are over 150 other optional props.
716
- *
717
- * See more info on creating columns and data on the official docs site:
718
- * @link https://www.material-react-table.com/docs/usage
719
- *
720
- * See the full props list on the official docs site:
721
- * @link https://www.material-react-table.com/docs/api/props
722
- */
723
778
  export default <TData extends Record<string, any> = {}>({
724
779
  autoResetExpanded = false,
725
780
  columnResizeMode = 'onEnd',
@@ -1,4 +1,4 @@
1
- import React, { DragEvent, FC, MouseEvent, useMemo } from 'react';
1
+ import React, { DragEvent, FC, MouseEvent, RefObject, useMemo } from 'react';
2
2
  import {
3
3
  alpha,
4
4
  darken,
@@ -10,11 +10,13 @@ import {
10
10
  import { MRT_EditCellTextField } from '../inputs/MRT_EditCellTextField';
11
11
  import { MRT_CopyButton } from '../buttons/MRT_CopyButton';
12
12
  import type { MRT_Cell, MRT_TableInstance } from '..';
13
+ import { MRT_TableBodyRowGrabHandle } from './MRT_TableBodyRowGrabHandle';
13
14
 
14
15
  interface Props {
15
16
  cell: MRT_Cell;
16
17
  enableHover?: boolean;
17
18
  rowIndex: number;
19
+ rowRef: RefObject<HTMLTableRowElement>;
18
20
  table: MRT_TableInstance;
19
21
  }
20
22
 
@@ -22,6 +24,7 @@ export const MRT_TableBodyCell: FC<Props> = ({
22
24
  cell,
23
25
  enableHover,
24
26
  rowIndex,
27
+ rowRef,
25
28
  table,
26
29
  }) => {
27
30
  const theme = useTheme();
@@ -30,6 +33,7 @@ export const MRT_TableBodyCell: FC<Props> = ({
30
33
  options: {
31
34
  editingMode,
32
35
  enableClickToCopy,
36
+ enableColumnOrdering,
33
37
  enableEditing,
34
38
  enableRowNumbers,
35
39
  muiTableBodyCellProps,
@@ -124,7 +128,7 @@ export const MRT_TableBodyCell: FC<Props> = ({
124
128
  };
125
129
 
126
130
  const handleDragEnter = (_e: DragEvent) => {
127
- if (currentDraggingColumn) {
131
+ if (enableColumnOrdering && currentDraggingColumn) {
128
132
  setCurrentHoveredColumn(columnDefType === 'data' ? column : null);
129
133
  }
130
134
  };
@@ -140,6 +144,10 @@ export const MRT_TableBodyCell: FC<Props> = ({
140
144
  ? {
141
145
  borderLeft: draggingBorder,
142
146
  borderRight: draggingBorder,
147
+ borderBottom:
148
+ row.index === table.getRowModel().rows.length - 1
149
+ ? draggingBorder
150
+ : undefined,
143
151
  }
144
152
  : undefined;
145
153
 
@@ -181,7 +189,7 @@ export const MRT_TableBodyCell: FC<Props> = ({
181
189
  ? '1rem 1.25rem'
182
190
  : '1.5rem',
183
191
  pl:
184
- column.id === 'mrt-expand'
192
+ column.id === 'mrt-row-expand'
185
193
  ? `${
186
194
  row.depth +
187
195
  (density === 'compact'
@@ -233,6 +241,12 @@ export const MRT_TableBodyCell: FC<Props> = ({
233
241
  rowNumberMode === 'static' &&
234
242
  column.id === 'mrt-row-numbers' ? (
235
243
  rowIndex + 1
244
+ ) : column.id === 'mrt-row-drag' ? (
245
+ <MRT_TableBodyRowGrabHandle
246
+ cell={cell}
247
+ rowRef={rowRef}
248
+ table={table}
249
+ />
236
250
  ) : columnDefType === 'display' ? (
237
251
  columnDef.Cell?.({ cell, table })
238
252
  ) : isEditing ? (
@@ -1,5 +1,5 @@
1
- import React, { FC } from 'react';
2
- import { darken, lighten, TableRow } from '@mui/material';
1
+ import React, { DragEvent, FC, useRef } from 'react';
2
+ import { darken, lighten, TableRow, useTheme } from '@mui/material';
3
3
  import { MRT_TableBodyCell } from './MRT_TableBodyCell';
4
4
  import { MRT_TableDetailPanel } from './MRT_TableDetailPanel';
5
5
  import type { MRT_Row, MRT_TableInstance } from '..';
@@ -11,24 +11,56 @@ interface Props {
11
11
  }
12
12
 
13
13
  export const MRT_TableBodyRow: FC<Props> = ({ row, rowIndex, table }) => {
14
+ const theme = useTheme();
14
15
  const {
15
16
  getIsSomeColumnsPinned,
16
- options: { muiTableBodyRowProps, renderDetailPanel },
17
+ getState,
18
+ options: { enableRowOrdering, muiTableBodyRowProps, renderDetailPanel },
19
+ setCurrentHoveredRow,
17
20
  } = table;
21
+ const { currentDraggingRow, currentHoveredRow } = getState();
18
22
 
19
23
  const tableRowProps =
20
24
  muiTableBodyRowProps instanceof Function
21
25
  ? muiTableBodyRowProps({ row, table })
22
26
  : muiTableBodyRowProps;
23
27
 
28
+ const handleDragEnter = (_e: DragEvent) => {
29
+ if (enableRowOrdering && currentDraggingRow) {
30
+ setCurrentHoveredRow(row);
31
+ }
32
+ };
33
+
34
+ const rowRef = useRef<HTMLTableRowElement>(null);
35
+
36
+ const draggingBorder =
37
+ currentDraggingRow?.id === row.id
38
+ ? `1px dashed ${theme.palette.divider}`
39
+ : currentHoveredRow?.id === row.id
40
+ ? `2px dashed ${theme.palette.primary.main}`
41
+ : undefined;
42
+
43
+ const draggingBorders = draggingBorder
44
+ ? {
45
+ border: draggingBorder,
46
+ }
47
+ : undefined;
48
+
24
49
  return (
25
50
  <>
26
51
  <TableRow
52
+ onDragEnter={handleDragEnter}
27
53
  hover
28
54
  selected={row.getIsSelected()}
55
+ ref={rowRef}
29
56
  {...tableRowProps}
30
57
  sx={(theme) => ({
31
58
  backgroundColor: lighten(theme.palette.background.default, 0.06),
59
+ opacity:
60
+ currentDraggingRow?.id === row.id ||
61
+ currentHoveredRow?.id === row.id
62
+ ? 0.5
63
+ : 1,
32
64
  transition: 'all 0.2s ease-in-out',
33
65
  '&:hover td': {
34
66
  backgroundColor:
@@ -39,6 +71,7 @@ export const MRT_TableBodyRow: FC<Props> = ({ row, rowIndex, table }) => {
39
71
  : undefined,
40
72
  },
41
73
  ...(tableRowProps?.sx as any),
74
+ ...draggingBorders,
42
75
  })}
43
76
  >
44
77
  {row?.getVisibleCells()?.map?.((cell) => (
@@ -47,6 +80,7 @@ export const MRT_TableBodyRow: FC<Props> = ({ row, rowIndex, table }) => {
47
80
  key={cell.id}
48
81
  enableHover={tableRowProps?.hover !== false}
49
82
  rowIndex={rowIndex}
83
+ rowRef={rowRef}
50
84
  table={table}
51
85
  />
52
86
  ))}
@@ -0,0 +1,48 @@
1
+ import React, { DragEvent, FC, RefObject } from 'react';
2
+ import { MRT_Cell, MRT_TableInstance } from '..';
3
+ import { MRT_GrabHandleButton } from '../buttons/MRT_GrabHandleButton';
4
+
5
+ interface Props {
6
+ cell: MRT_Cell;
7
+ rowRef: RefObject<HTMLTableRowElement>;
8
+ table: MRT_TableInstance;
9
+ }
10
+
11
+ export const MRT_TableBodyRowGrabHandle: FC<Props> = ({
12
+ cell,
13
+ rowRef,
14
+ table,
15
+ }) => {
16
+ const {
17
+ options: { muiTableBodyRowDragHandleProps, onRowDrop },
18
+ } = table;
19
+
20
+ const iconButtonProps =
21
+ muiTableBodyRowDragHandleProps instanceof Function
22
+ ? muiTableBodyRowDragHandleProps({ row: cell.row, table })
23
+ : muiTableBodyRowDragHandleProps;
24
+
25
+ const handleDragStart = (e: DragEvent<HTMLButtonElement>) => {
26
+ e.dataTransfer.setDragImage(rowRef.current as HTMLElement, 0, 0);
27
+ table.setCurrentDraggingRow(cell.row as any);
28
+ };
29
+
30
+ const handleDragEnd = (event: DragEvent<HTMLButtonElement>) => {
31
+ onRowDrop?.({
32
+ event,
33
+ draggedRow: table.getState().currentDraggingRow as any,
34
+ targetRow: table.getState().currentHoveredRow as any,
35
+ });
36
+ table.setCurrentDraggingRow(null);
37
+ table.setCurrentHoveredRow(null);
38
+ };
39
+
40
+ return (
41
+ <MRT_GrabHandleButton
42
+ iconButtonProps={iconButtonProps}
43
+ onDragStart={handleDragStart}
44
+ onDragEnd={handleDragEnd}
45
+ table={table}
46
+ />
47
+ );
48
+ };
@@ -1,16 +1,18 @@
1
- import { IconButton, Tooltip } from '@mui/material';
1
+ import { IconButton, IconButtonProps, Tooltip } from '@mui/material';
2
2
  import React, { DragEventHandler, FC } from 'react';
3
3
  import { MRT_TableInstance } from '..';
4
4
 
5
5
  interface Props {
6
- handleDragStart: DragEventHandler<HTMLButtonElement>;
7
- handleDragEnd: DragEventHandler<HTMLButtonElement>;
6
+ iconButtonProps?: IconButtonProps;
7
+ onDragStart: DragEventHandler<HTMLButtonElement>;
8
+ onDragEnd: DragEventHandler<HTMLButtonElement>;
8
9
  table: MRT_TableInstance;
9
10
  }
10
11
 
11
12
  export const MRT_GrabHandleButton: FC<Props> = ({
12
- handleDragStart,
13
- handleDragEnd,
13
+ iconButtonProps,
14
+ onDragEnd,
15
+ onDragStart,
14
16
  table,
15
17
  }) => {
16
18
  const {
@@ -26,14 +28,15 @@ export const MRT_GrabHandleButton: FC<Props> = ({
26
28
  enterDelay={1000}
27
29
  enterNextDelay={1000}
28
30
  placement="top"
29
- title={localization.grab}
31
+ title={localization.move}
30
32
  >
31
33
  <IconButton
32
34
  disableRipple
33
35
  draggable="true"
34
- onDragStart={handleDragStart}
35
- onDragEnd={handleDragEnd}
36
+ onDragStart={onDragStart}
37
+ onDragEnd={onDragEnd}
36
38
  size="small"
39
+ {...iconButtonProps}
37
40
  sx={{
38
41
  cursor: 'grab',
39
42
  m: 0,
@@ -47,6 +50,7 @@ export const MRT_GrabHandleButton: FC<Props> = ({
47
50
  '&:active': {
48
51
  cursor: 'grabbing',
49
52
  },
53
+ ...iconButtonProps?.sx,
50
54
  }}
51
55
  >
52
56
  <DragHandleIcon />
@@ -1,12 +1,11 @@
1
1
  import React, { DragEvent, FC, ReactNode } from 'react';
2
2
  import { Box, TableCell, Theme, alpha, lighten, useTheme } from '@mui/material';
3
+ import { MRT_TableHeadCellColumnActionsButton } from './MRT_TableHeadCellColumnActionsButton';
3
4
  import { MRT_TableHeadCellFilterContainer } from './MRT_TableHeadCellFilterContainer';
4
5
  import { MRT_TableHeadCellFilterLabel } from './MRT_TableHeadCellFilterLabel';
5
- import { MRT_GrabHandleButton } from '../buttons/MRT_GrabHandleButton';
6
+ import { MRT_TableHeadCellGrabHandle } from './MRT_TableHeadCellGrabHandle';
6
7
  import { MRT_TableHeadCellResizeHandle } from './MRT_TableHeadCellResizeHandle';
7
8
  import { MRT_TableHeadCellSortLabel } from './MRT_TableHeadCellSortLabel';
8
- import { MRT_TableHeadCellColumnActionsButton } from './MRT_TableHeadCellColumnActionsButton';
9
- import { reorderColumn } from '../utils';
10
9
  import type { MRT_Header, MRT_TableInstance } from '..';
11
10
 
12
11
  interface Props {
@@ -20,18 +19,16 @@ export const MRT_TableHeadCell: FC<Props> = ({ header, table }) => {
20
19
  getState,
21
20
  options: {
22
21
  enableColumnActions,
22
+ enableColumnDragging,
23
23
  enableColumnOrdering,
24
24
  enableColumnResizing,
25
25
  enableGrouping,
26
26
  enableMultiSort,
27
27
  muiTableHeadCellProps,
28
28
  },
29
- setColumnOrder,
30
- setCurrentDraggingColumn,
31
29
  setCurrentHoveredColumn,
32
30
  } = table;
33
- const { columnOrder, density, currentDraggingColumn, currentHoveredColumn } =
34
- getState();
31
+ const { density, currentDraggingColumn, currentHoveredColumn } = getState();
35
32
  const { column } = header;
36
33
  const { columnDef } = column;
37
34
  const { columnDefType } = columnDef;
@@ -75,30 +72,14 @@ export const MRT_TableHeadCell: FC<Props> = ({ header, table }) => {
75
72
  );
76
73
  };
77
74
 
78
- const tableHeadCellRef = React.useRef<HTMLElement>(null);
79
-
80
- const handleDragStart = (e: DragEvent<HTMLButtonElement>) => {
81
- setCurrentDraggingColumn(column);
82
- e.dataTransfer.setDragImage(tableHeadCellRef.current as HTMLElement, 0, 0);
83
- };
84
-
85
- const handleDragEnd = (_e: DragEvent<HTMLButtonElement>) => {
86
- setCurrentDraggingColumn(null);
87
- setCurrentHoveredColumn(null);
88
- if (
89
- currentHoveredColumn &&
90
- currentHoveredColumn?.id !== currentDraggingColumn?.id
91
- ) {
92
- setColumnOrder(reorderColumn(column, currentHoveredColumn, columnOrder));
93
- }
94
- };
95
-
96
75
  const handleDragEnter = (_e: DragEvent) => {
97
- if (currentDraggingColumn) {
76
+ if (enableColumnOrdering && currentDraggingColumn) {
98
77
  setCurrentHoveredColumn(columnDefType === 'data' ? column : null);
99
78
  }
100
79
  };
101
80
 
81
+ const tableHeadCellRef = React.useRef<HTMLTableCellElement>(null);
82
+
102
83
  const draggingBorder =
103
84
  currentDraggingColumn?.id === column.id
104
85
  ? `1px dashed ${theme.palette.divider}`
@@ -223,13 +204,15 @@ export const MRT_TableHeadCell: FC<Props> = ({ header, table }) => {
223
204
  </Box>
224
205
  <Box sx={{ whiteSpace: 'nowrap' }}>
225
206
  {columnDefType === 'data' &&
226
- ((enableColumnOrdering &&
227
- columnDef.enableColumnOrdering !== false) ||
207
+ ((enableColumnDragging &&
208
+ columnDef.enableColumnDragging !== false) ||
209
+ (enableColumnOrdering &&
210
+ columnDef.enableColumnOrdering !== false) ||
228
211
  (enableGrouping && columnDef.enableGrouping !== false)) && (
229
- <MRT_GrabHandleButton
230
- handleDragStart={handleDragStart}
231
- handleDragEnd={handleDragEnd}
212
+ <MRT_TableHeadCellGrabHandle
213
+ column={column}
232
214
  table={table}
215
+ tableHeadCellRef={tableHeadCellRef}
233
216
  />
234
217
  )}
235
218
  {(enableColumnActions || columnDef.enableColumnActions) &&
@@ -0,0 +1,77 @@
1
+ import React, { DragEvent, FC, RefObject } from 'react';
2
+ import { MRT_GrabHandleButton } from '../buttons/MRT_GrabHandleButton';
3
+ import { reorderColumn } from '../utils';
4
+ import type { MRT_Column, MRT_TableInstance } from '..';
5
+
6
+ interface Props {
7
+ column: MRT_Column;
8
+ table: MRT_TableInstance;
9
+ tableHeadCellRef: RefObject<HTMLTableCellElement>;
10
+ }
11
+
12
+ export const MRT_TableHeadCellGrabHandle: FC<Props> = ({
13
+ column,
14
+ table,
15
+ tableHeadCellRef,
16
+ }) => {
17
+ const {
18
+ getState,
19
+ options: {
20
+ enableColumnOrdering,
21
+ muiTableHeadCellDragHandleProps,
22
+ onColumnDrop,
23
+ },
24
+ setColumnOrder,
25
+ setCurrentDraggingColumn,
26
+ setCurrentHoveredColumn,
27
+ } = table;
28
+ const { columnDef } = column;
29
+ const { currentHoveredColumn, currentDraggingColumn, columnOrder } =
30
+ getState();
31
+
32
+ const mIconButtonProps =
33
+ muiTableHeadCellDragHandleProps instanceof Function
34
+ ? muiTableHeadCellDragHandleProps({ column, table })
35
+ : muiTableHeadCellDragHandleProps;
36
+
37
+ const mcIconButtonProps =
38
+ columnDef.muiTableHeadCellDragHandleProps instanceof Function
39
+ ? columnDef.muiTableHeadCellDragHandleProps({ column, table })
40
+ : columnDef.muiTableHeadCellDragHandleProps;
41
+
42
+ const iconButtonProps = {
43
+ ...mIconButtonProps,
44
+ ...mcIconButtonProps,
45
+ };
46
+
47
+ const handleDragStart = (e: DragEvent<HTMLButtonElement>) => {
48
+ setCurrentDraggingColumn(column);
49
+ e.dataTransfer.setDragImage(tableHeadCellRef.current as HTMLElement, 0, 0);
50
+ };
51
+
52
+ const handleDragEnd = (event: DragEvent<HTMLButtonElement>) => {
53
+ onColumnDrop?.({
54
+ event,
55
+ draggedColumn: column,
56
+ targetColumn: currentHoveredColumn,
57
+ });
58
+ if (
59
+ enableColumnOrdering &&
60
+ currentHoveredColumn &&
61
+ currentHoveredColumn?.id !== currentDraggingColumn?.id
62
+ ) {
63
+ setColumnOrder(reorderColumn(column, currentHoveredColumn, columnOrder));
64
+ }
65
+ setCurrentDraggingColumn(null);
66
+ setCurrentHoveredColumn(null);
67
+ };
68
+
69
+ return (
70
+ <MRT_GrabHandleButton
71
+ iconButtonProps={iconButtonProps}
72
+ onDragStart={handleDragStart}
73
+ onDragEnd={handleDragEnd}
74
+ table={table}
75
+ />
76
+ );
77
+ };
@@ -34,6 +34,7 @@ export interface MRT_Localization {
34
34
  hideColumn: string;
35
35
  max: string;
36
36
  min: string;
37
+ move: string;
37
38
  pinToLeft: string;
38
39
  pinToRight: string;
39
40
  resetColumnSize: string;
@@ -102,6 +103,7 @@ export const MRT_DefaultLocalization_EN: MRT_Localization = {
102
103
  hideColumn: 'Hide {column} column',
103
104
  max: 'Max',
104
105
  min: 'Min',
106
+ move: 'Move',
105
107
  pinToLeft: 'Pin to left',
106
108
  pinToRight: 'Pin to right',
107
109
  resetColumnSize: 'Reset column size',
@@ -100,7 +100,7 @@ export const MRT_ColumnActionMenu: FC<Props> = ({
100
100
 
101
101
  const handleGroupByColumn = () => {
102
102
  column.toggleGrouping();
103
- setColumnOrder((old) => ['mrt-expand', ...old]);
103
+ setColumnOrder((old) => ['mrt-row-expand', ...old]);
104
104
  setAnchorEl(null);
105
105
  };
106
106