@purpurds/table 8.3.0 → 8.4.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.
Files changed (82) hide show
  1. package/dist/LICENSE.txt +205 -35
  2. package/dist/drag-indicator-circle.d.ts +13 -0
  3. package/dist/drag-indicator-circle.d.ts.map +1 -0
  4. package/dist/draggable-table.d.ts +23 -0
  5. package/dist/draggable-table.d.ts.map +1 -0
  6. package/dist/empty-table.d.ts +14 -0
  7. package/dist/empty-table.d.ts.map +1 -0
  8. package/dist/loading-table-rows.d.ts +13 -0
  9. package/dist/loading-table-rows.d.ts.map +1 -0
  10. package/dist/styles.css +1 -1
  11. package/dist/table-body.d.ts +2 -2
  12. package/dist/table-body.d.ts.map +1 -1
  13. package/dist/table-column-header-cell.d.ts +15 -2
  14. package/dist/table-column-header-cell.d.ts.map +1 -1
  15. package/dist/table-content.d.ts +42 -0
  16. package/dist/table-content.d.ts.map +1 -0
  17. package/dist/table-headers.d.ts +28 -0
  18. package/dist/table-headers.d.ts.map +1 -0
  19. package/dist/table-row-cell-skeleton.d.ts +1 -1
  20. package/dist/table-row-cell-skeleton.d.ts.map +1 -1
  21. package/dist/table-row-cell.d.ts +5 -2
  22. package/dist/table-row-cell.d.ts.map +1 -1
  23. package/dist/table-row.d.ts +2 -2
  24. package/dist/table-row.d.ts.map +1 -1
  25. package/dist/table-settings-drawer.d.ts +44 -11
  26. package/dist/table-settings-drawer.d.ts.map +1 -1
  27. package/dist/table.cjs.js +89 -85
  28. package/dist/table.cjs.js.map +1 -1
  29. package/dist/table.d.ts +3 -3
  30. package/dist/table.d.ts.map +1 -1
  31. package/dist/table.es.js +14397 -10195
  32. package/dist/table.es.js.map +1 -1
  33. package/dist/test-utils/helpers.d.ts +1 -0
  34. package/dist/test-utils/helpers.d.ts.map +1 -1
  35. package/dist/types.d.ts +23 -2
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/use-drag-handle.hook.d.ts +15 -0
  38. package/dist/use-drag-handle.hook.d.ts.map +1 -0
  39. package/dist/use-drag-indicator-position.hook.d.ts +19 -0
  40. package/dist/use-drag-indicator-position.hook.d.ts.map +1 -0
  41. package/dist/use-drop-indicator.hook.d.ts +15 -0
  42. package/dist/use-drop-indicator.hook.d.ts.map +1 -0
  43. package/dist/use-element-visibility.hook.d.ts +4 -0
  44. package/dist/use-element-visibility.hook.d.ts.map +1 -0
  45. package/dist/use-table-scroll.hook.d.ts +6 -0
  46. package/dist/use-table-scroll.hook.d.ts.map +1 -0
  47. package/dist/utils/custom-keyboard-coordinates.d.ts +8 -0
  48. package/dist/utils/custom-keyboard-coordinates.d.ts.map +1 -0
  49. package/package.json +27 -23
  50. package/src/drag-indicator-circle.tsx +36 -0
  51. package/src/draggable-table.test.tsx +381 -0
  52. package/src/draggable-table.tsx +191 -0
  53. package/src/empty-table.tsx +54 -0
  54. package/src/loading-table-rows.tsx +41 -0
  55. package/src/table-body.tsx +1 -3
  56. package/src/table-column-header-cell.tsx +135 -64
  57. package/src/table-content-drag.test.tsx +505 -0
  58. package/src/table-content.tsx +165 -0
  59. package/src/table-dnd-integration.test.tsx +425 -0
  60. package/src/table-drag-and-drop.test.tsx +276 -0
  61. package/src/table-headers.tsx +118 -0
  62. package/src/table-row-cell-skeleton.tsx +1 -1
  63. package/src/table-row-cell.test.tsx +2 -1
  64. package/src/table-row-cell.tsx +42 -31
  65. package/src/table-row.tsx +1 -3
  66. package/src/table-settings-drawer.module.scss +165 -2
  67. package/src/table-settings-drawer.test.tsx +0 -99
  68. package/src/table-settings-drawer.tsx +359 -53
  69. package/src/table.module.scss +191 -30
  70. package/src/table.stories.tsx +60 -4
  71. package/src/table.test.tsx +5 -1
  72. package/src/table.tsx +255 -213
  73. package/src/test-utils/helpers.ts +2 -0
  74. package/src/types.ts +25 -2
  75. package/src/use-drag-handle.hook.tsx +60 -0
  76. package/src/use-drag-handle.test.tsx +380 -0
  77. package/src/use-drag-indicator-position.hook.ts +74 -0
  78. package/src/use-drop-indicator.hook.ts +46 -0
  79. package/src/use-element-visibility.hook.ts +28 -0
  80. package/src/use-table-scroll.hook.tsx +30 -0
  81. package/src/utils/custom-keyboard-coordinates.ts +83 -0
  82. package/vitest.setup.ts +1 -1
@@ -1,15 +1,46 @@
1
- import React, { useId } from "react";
1
+ import React, { useId, useState } from "react";
2
+ import {
3
+ closestCenter,
4
+ DndContext,
5
+ type DragEndEvent,
6
+ DragOverlay,
7
+ type DragStartEvent,
8
+ KeyboardSensor,
9
+ PointerSensor,
10
+ TouchSensor,
11
+ type UniqueIdentifier,
12
+ useSensor,
13
+ useSensors,
14
+ } from "@dnd-kit/core";
15
+ import { restrictToParentElement, restrictToVerticalAxis } from "@dnd-kit/modifiers";
16
+ import {
17
+ arrayMove,
18
+ SortableContext,
19
+ sortableKeyboardCoordinates,
20
+ useSortable,
21
+ verticalListSortingStrategy,
22
+ } from "@dnd-kit/sortable";
2
23
  import { Button } from "@purpurds/button";
3
24
  import { Drawer } from "@purpurds/drawer";
4
25
  import { Heading } from "@purpurds/heading";
26
+ import { IconArrowDown } from "@purpurds/icon/arrow-down";
27
+ import { IconArrowUp } from "@purpurds/icon/arrow-up";
28
+ import { IconDragVertical } from "@purpurds/icon/drag-vertical";
29
+ import { IconSorter } from "@purpurds/icon/sorter";
5
30
  import { IconSync } from "@purpurds/icon/sync";
31
+ import { Paragraph } from "@purpurds/paragraph";
6
32
  import { Toggle } from "@purpurds/toggle";
33
+ import {
34
+ purpurMotionDuration150,
35
+ purpurMotionEasingEaseInOut,
36
+ } from "@purpurds/tokens/motion/variables";
7
37
  import { type Column, type RowData } from "@tanstack/react-table";
8
38
  import c from "classnames/bind";
9
39
 
10
40
  import styles from "./table-settings-drawer.module.scss";
41
+ import { useDropIndicator } from "./use-drop-indicator.hook";
11
42
 
12
- export type TableSettingsDrawerCopyProps = {
43
+ export type TableSettingsDrawerCopyProps<TEnableDrag extends boolean = boolean> = {
13
44
  title: string;
14
45
  generalSettings: {
15
46
  header: string;
@@ -17,18 +48,60 @@ export type TableSettingsDrawerCopyProps = {
17
48
  showFilters: string;
18
49
  lockFirstcolumn: string;
19
50
  stickyHeader: string;
20
- rowSelection?: string;
21
51
  };
22
52
  };
23
- visibleColumns: {
24
- header: string;
25
- };
53
+ visibleColumns: TEnableDrag extends true
54
+ ? VisibleColumnsWithColumnDragCopyProps
55
+ : VisibleColumnsWithoutColumnDragCopyProps;
26
56
  buttons: {
27
57
  closeDrawer: string;
28
58
  resetSettings: string;
29
59
  };
30
60
  };
31
61
 
62
+ type VisibleColumnsCopyBaseProps = {
63
+ header: string;
64
+ description: string;
65
+ };
66
+
67
+ type VisibleColumnsWithColumnDragCopyProps = VisibleColumnsCopyBaseProps & {
68
+ rearrangeDescription: string;
69
+ buttons: {
70
+ rearrange: string;
71
+ done: string;
72
+ };
73
+ ariaLabels: {
74
+ dragHandle: {
75
+ action: string;
76
+ instructions: string;
77
+ };
78
+ arrowButtons: {
79
+ move: string;
80
+ up: string;
81
+ down: string;
82
+ };
83
+ rearrangeButton: string;
84
+ };
85
+ };
86
+
87
+ type VisibleColumnsWithoutColumnDragCopyProps = VisibleColumnsCopyBaseProps & {
88
+ rearrangeDescription?: never;
89
+ buttons?: never;
90
+ ariaLabels?: never;
91
+ };
92
+
93
+ type ColumnDragEnabledProps = {
94
+ enableColumnDrag: true;
95
+ onColumnOrderChange: (newColumnOrder: string[]) => void;
96
+ copy: TableSettingsDrawerCopyProps<true>;
97
+ };
98
+
99
+ type ColumnDragDisabledProps = {
100
+ enableColumnDrag?: false;
101
+ onColumnOrderChange?: never;
102
+ copy: TableSettingsDrawerCopyProps<false>;
103
+ };
104
+
32
105
  export type TableSettingsDrawerProps<TData> = {
33
106
  id: string;
34
107
  getAllColumns: () => Column<TData, unknown>[];
@@ -38,16 +111,13 @@ export type TableSettingsDrawerProps<TData> = {
38
111
  setStickyFirstColumn: React.Dispatch<React.SetStateAction<boolean>>;
39
112
  setStickyHeaders: React.Dispatch<React.SetStateAction<boolean>>;
40
113
  columnFiltersEnabled: boolean;
41
- copy: TableSettingsDrawerCopyProps;
42
114
  isDrawerOpen: boolean;
43
115
  showColumnFilters: boolean;
44
116
  stickyFirstColumn: boolean;
45
117
  stickyHeaders: boolean;
46
- enableRowSelection?: boolean;
47
- rowSelectionEnabled?: boolean;
48
- setRowSelectionEnabled?: React.Dispatch<React.SetStateAction<boolean>>;
49
118
  zIndex?: number;
50
- };
119
+ columnOrder?: string[];
120
+ } & (ColumnDragEnabledProps | ColumnDragDisabledProps);
51
121
 
52
122
  const rootClassName = "purpur-table-settings-drawer";
53
123
  const cx = c.bind(styles);
@@ -67,10 +137,10 @@ export const TableSettingsDrawer = <TData extends RowData>({
67
137
  setShowColumnFiltersEnabled,
68
138
  setStickyFirstColumn,
69
139
  setStickyHeaders,
70
- enableRowSelection,
71
- rowSelectionEnabled,
72
- setRowSelectionEnabled,
140
+ enableColumnDrag,
73
141
  zIndex,
142
+ columnOrder,
143
+ onColumnOrderChange,
74
144
  }: TableSettingsDrawerProps<TData>) => {
75
145
  return (
76
146
  <div id={id}>
@@ -96,11 +166,22 @@ export const TableSettingsDrawer = <TData extends RowData>({
96
166
  stickyFirstColumn={stickyFirstColumn}
97
167
  stickyHeaders={stickyHeaders}
98
168
  copy={copy.generalSettings}
99
- enableRowSelection={enableRowSelection}
100
- rowSelectionEnabled={rowSelectionEnabled}
101
- setRowSelectionEnabled={setRowSelectionEnabled}
102
169
  />
103
- <VisibleColumns getAllColumns={getAllColumns} header={copy.visibleColumns.header} />
170
+ <VisibleColumns
171
+ getAllColumns={getAllColumns}
172
+ header={copy.visibleColumns.header}
173
+ columnOrder={columnOrder}
174
+ {...(enableColumnDrag
175
+ ? {
176
+ enableColumnDrag: true,
177
+ onColumnOrderChange: onColumnOrderChange,
178
+ copy: copy as TableSettingsDrawerCopyProps<true>,
179
+ }
180
+ : {
181
+ enableColumnDrag: false,
182
+ copy: copy as TableSettingsDrawerCopyProps<false>,
183
+ })}
184
+ />
104
185
  </div>
105
186
  </Drawer.Content>
106
187
  </Drawer>
@@ -131,12 +212,8 @@ type GeneralSettingsProps = {
131
212
  showFilters: string;
132
213
  lockFirstcolumn: string;
133
214
  stickyHeader: string;
134
- rowSelection?: string;
135
215
  };
136
216
  };
137
- enableRowSelection?: boolean;
138
- rowSelectionEnabled?: boolean;
139
- setRowSelectionEnabled?: React.Dispatch<React.SetStateAction<boolean>>;
140
217
  };
141
218
 
142
219
  const GeneralSettings = ({
@@ -148,9 +225,6 @@ const GeneralSettings = ({
148
225
  stickyFirstColumn,
149
226
  stickyHeaders,
150
227
  copy,
151
- enableRowSelection,
152
- rowSelectionEnabled,
153
- setRowSelectionEnabled,
154
228
  }: GeneralSettingsProps) => {
155
229
  const uid = useId();
156
230
  return (
@@ -182,14 +256,6 @@ const GeneralSettings = ({
182
256
  label={copy.toggles.stickyHeader}
183
257
  onChange={setStickyHeaders}
184
258
  />
185
- {enableRowSelection && copy.toggles.rowSelection && setRowSelectionEnabled && (
186
- <ToggleWrapper
187
- id={`${uid}-row-selection`}
188
- checked={rowSelectionEnabled || false}
189
- label={copy.toggles.rowSelection}
190
- onChange={setRowSelectionEnabled}
191
- />
192
- )}
193
259
  </div>
194
260
  );
195
261
  };
@@ -197,44 +263,254 @@ const GeneralSettings = ({
197
263
  const VisibleColumns = <TData extends RowData>({
198
264
  header,
199
265
  getAllColumns,
266
+ enableColumnDrag,
267
+ columnOrder,
268
+ onColumnOrderChange,
269
+ copy,
200
270
  }: {
201
271
  header: string;
202
272
  getAllColumns: () => Column<TData, unknown>[];
203
- }) => {
273
+ columnOrder?: string[];
274
+ } & (ColumnDragDisabledProps | ColumnDragEnabledProps)) => {
204
275
  const allColumns = getAllColumns();
205
- // Filter out row-selection and row-toggle columns
206
- const filteredColumns = allColumns.filter(
207
- (column) => column.id !== "row-selection" && column.id !== "row-toggle"
276
+
277
+ const filterAwayRowSelectionToggle = (column: Column<TData, unknown>) =>
278
+ column.id !== "row-selection" && column.id !== "row-toggle";
279
+
280
+ const [isRearrangeMode, setIsRearrangeMode] = useState(false);
281
+ const [activeId, setActiveId] = useState<UniqueIdentifier | null>(null);
282
+
283
+ const visible = allColumns
284
+ .filter((column) => column.getIsVisible())
285
+ .filter(filterAwayRowSelectionToggle);
286
+
287
+ const sensors = useSensors(
288
+ useSensor(PointerSensor),
289
+ useSensor(TouchSensor),
290
+ useSensor(KeyboardSensor, {
291
+ coordinateGetter: sortableKeyboardCoordinates,
292
+ })
208
293
  );
209
- const visible = filteredColumns.filter((column) => column.getIsVisible());
210
294
 
211
- const isDisabled = (column: Column<TData, unknown>) => {
212
- return !column.getCanHide() || (visible.length === 1 && visible.includes(column));
295
+ const handleDragStart = (event: DragStartEvent) => {
296
+ setActiveId(event.active.id);
213
297
  };
298
+
299
+ const handleDragEnd = (event: DragEndEvent) => {
300
+ const { active, over } = event;
301
+
302
+ if (over && active.id !== over.id) {
303
+ const currentOrder = allColumns.map((column) => column.id);
304
+
305
+ const oldIndex = currentOrder.indexOf(String(active.id));
306
+ const newIndex = currentOrder.indexOf(String(over.id));
307
+
308
+ if (oldIndex !== -1 && newIndex !== -1) {
309
+ const newOrder = [...currentOrder];
310
+ const [removed] = newOrder.splice(oldIndex, 1);
311
+ newOrder.splice(newIndex, 0, removed);
312
+
313
+ if (onColumnOrderChange) onColumnOrderChange(newOrder);
314
+ }
315
+ }
316
+
317
+ setActiveId(null);
318
+ };
319
+
320
+ const moveColumn = (id: string, direction: "up" | "down") => {
321
+ const currentOrder = allColumns.map((column) => column.id);
322
+
323
+ const index = currentOrder.indexOf(id);
324
+ if (
325
+ (direction === "up" && index === 0) ||
326
+ (direction === "down" && index === currentOrder.length - 1)
327
+ ) {
328
+ return;
329
+ }
330
+ const newIndex = direction === "up" ? index - 1 : index + 1;
331
+ const newOrder = arrayMove(currentOrder, index, newIndex);
332
+ if (onColumnOrderChange) onColumnOrderChange(newOrder);
333
+ };
334
+
335
+ const getColumnById = (id: string) => allColumns.find((col) => col.id === id);
336
+
337
+ const isDisabled = (column: Column<TData, unknown>) =>
338
+ !column.getCanHide() || (visible.length === 1 && visible.includes(column));
339
+
214
340
  const uid = useId();
341
+
342
+ const activeColumn = activeId ? getColumnById(String(activeId)) : null;
343
+ const filteredColumns = allColumns.filter(filterAwayRowSelectionToggle);
344
+
215
345
  return (
216
346
  <section
217
347
  data-testid={`${rootTestId}-visible-columns`}
218
348
  className={cx(`${rootClassName}__visible-columns`)}
219
349
  aria-labelledby={`${uid}-visible-columns`}
220
350
  >
221
- <Heading id={`${uid}-visible-columns`} variant="title-100" tag="h3">
222
- {header}
223
- </Heading>
224
- {filteredColumns.map((column) => (
225
- <ToggleWrapper
226
- key={column.id}
227
- id={column.id}
228
- checked={column.getIsVisible()}
229
- disabled={isDisabled(column)}
230
- label={column.columnDef.header as string}
231
- onChange={() => column.toggleVisibility()}
232
- />
233
- ))}
351
+ <div className={cx(`${rootClassName}__visible-columns-header-wrapper`)}>
352
+ <div className={cx(`${rootClassName}__visible-columns-header`)}>
353
+ <Heading id={`${uid}-visible-columns`} variant="title-100" tag="h3">
354
+ {header}
355
+ </Heading>
356
+ {enableColumnDrag && (
357
+ <Button
358
+ variant={isRearrangeMode ? "primary" : "tertiary-purple"}
359
+ onClick={() => setIsRearrangeMode((v) => !v)}
360
+ data-testid={`${rootTestId}-rearrange-button`}
361
+ aria-label={copy.visibleColumns.ariaLabels.rearrangeButton}
362
+ >
363
+ <IconSorter size="xs" />
364
+ {isRearrangeMode
365
+ ? copy.visibleColumns.buttons.done
366
+ : copy.visibleColumns.buttons.rearrange}
367
+ </Button>
368
+ )}
369
+ </div>
370
+ <Paragraph>
371
+ {isRearrangeMode && enableColumnDrag
372
+ ? copy.visibleColumns.rearrangeDescription
373
+ : copy.visibleColumns.description}
374
+ </Paragraph>
375
+ </div>
376
+ {isRearrangeMode && enableColumnDrag && columnOrder ? (
377
+ <div className={cx(`${rootClassName}__draggable-list`)}>
378
+ <DndContext
379
+ sensors={sensors}
380
+ collisionDetection={closestCenter}
381
+ onDragStart={handleDragStart}
382
+ onDragEnd={handleDragEnd}
383
+ modifiers={[restrictToVerticalAxis, restrictToParentElement]}
384
+ >
385
+ <SortableContext items={columnOrder} strategy={verticalListSortingStrategy}>
386
+ {filteredColumns.map((column, index) => {
387
+ return (
388
+ <DraggableColumnItemWithIndicator
389
+ key={column.id}
390
+ column={column}
391
+ moveColumn={moveColumn}
392
+ isFirst={index === 0}
393
+ isLast={index === filteredColumns.length - 1}
394
+ copy={copy}
395
+ index={index}
396
+ />
397
+ );
398
+ })}
399
+ </SortableContext>
400
+ <DragOverlay
401
+ dropAnimation={{
402
+ duration: Number(purpurMotionDuration150),
403
+ easing: purpurMotionEasingEaseInOut,
404
+ }}
405
+ >
406
+ {activeColumn ? (
407
+ <DraggableColumnItem
408
+ id={activeColumn.id}
409
+ label={activeColumn.columnDef.header as string}
410
+ onMoveUp={() => {}}
411
+ onMoveDown={() => {}}
412
+ overlay
413
+ copy={copy}
414
+ />
415
+ ) : null}
416
+ </DragOverlay>
417
+ </DndContext>
418
+ </div>
419
+ ) : (
420
+ filteredColumns.map((column) => (
421
+ <ToggleWrapper
422
+ key={column!.id}
423
+ id={column!.id}
424
+ checked={column!.getIsVisible()}
425
+ disabled={isDisabled(column!)}
426
+ label={column!.columnDef.header as string}
427
+ onChange={() => column!.toggleVisibility()}
428
+ />
429
+ ))
430
+ )}
234
431
  </section>
235
432
  );
236
433
  };
237
434
 
435
+ const DraggableColumnItem = ({
436
+ id,
437
+ label,
438
+ onMoveUp,
439
+ onMoveDown,
440
+ isFirst,
441
+ isLast,
442
+ overlay,
443
+ copy,
444
+ dropIndicatorPosition,
445
+ }: {
446
+ id: string;
447
+ label: string;
448
+ onMoveUp?: () => void;
449
+ onMoveDown?: () => void;
450
+ isFirst?: boolean;
451
+ isLast?: boolean;
452
+ overlay?: boolean;
453
+ copy: TableSettingsDrawerCopyProps<true>;
454
+ dropIndicatorPosition?: "before" | "after" | null;
455
+ }) => {
456
+ const { attributes, listeners, setNodeRef, isDragging } = useSortable({
457
+ id,
458
+ });
459
+
460
+ return (
461
+ <div
462
+ ref={setNodeRef}
463
+ className={cx(`${rootClassName}__draggable-item`, {
464
+ [`${rootClassName}__draggable-item--overlay`]: overlay,
465
+ [`${rootClassName}__draggable-item--dragging`]: isDragging,
466
+ [`${rootClassName}__draggable-item--drop-indicator-before`]:
467
+ dropIndicatorPosition === "before",
468
+ [`${rootClassName}__draggable-item--drop-indicator-after`]:
469
+ dropIndicatorPosition === "after",
470
+ })}
471
+ >
472
+ <div className={cx(`${rootClassName}__draggable-item-content`)}>
473
+ <div
474
+ className={cx(`${rootClassName}__draggable-handle`, {
475
+ [`${rootClassName}__draggable-handle--overlay`]: overlay,
476
+ })}
477
+ {...listeners}
478
+ {...attributes}
479
+ >
480
+ <IconDragVertical
481
+ className={cx(`${rootClassName}__draggable-handle-icon`, "terre")}
482
+ size="sm"
483
+ />
484
+ </div>
485
+ <span>{label}</span>
486
+ </div>
487
+
488
+ <div className={cx(`${rootClassName}__draggable-item-buttons`)}>
489
+ <Button
490
+ variant="secondary"
491
+ size="xs"
492
+ onClick={onMoveUp}
493
+ disabled={isFirst || overlay}
494
+ aria-label={`${copy.visibleColumns.ariaLabels.arrowButtons.move} ${label} ${copy.visibleColumns.ariaLabels.arrowButtons.up}`}
495
+ iconOnly
496
+ >
497
+ <IconArrowUp size="xs" />
498
+ </Button>
499
+ <Button
500
+ variant="secondary"
501
+ size="xs"
502
+ onClick={onMoveDown}
503
+ disabled={isLast || overlay}
504
+ aria-label={`${copy.visibleColumns.ariaLabels.arrowButtons.move} ${label} ${copy.visibleColumns.ariaLabels.arrowButtons.down}`}
505
+ iconOnly
506
+ >
507
+ <IconArrowDown size="xs" />
508
+ </Button>
509
+ </div>
510
+ </div>
511
+ );
512
+ };
513
+
238
514
  const ToggleWrapper = ({
239
515
  id,
240
516
  checked,
@@ -259,3 +535,33 @@ const ToggleWrapper = ({
259
535
  data-testid={`${rootTestId}-toggle`}
260
536
  />
261
537
  );
538
+
539
+ const DraggableColumnItemWithIndicator = <TData extends RowData>({
540
+ column,
541
+ moveColumn,
542
+ isFirst,
543
+ isLast,
544
+ copy,
545
+ }: {
546
+ column: Column<TData, unknown>;
547
+ moveColumn: (id: string, direction: "up" | "down") => void;
548
+ isFirst: boolean;
549
+ isLast: boolean;
550
+ copy: TableSettingsDrawerCopyProps<true>;
551
+ index: number;
552
+ }) => {
553
+ const dropIndicatorPosition = useDropIndicator({ itemId: column.id, enableDrag: true });
554
+
555
+ return (
556
+ <DraggableColumnItem
557
+ id={column.id}
558
+ label={column.columnDef.header as string}
559
+ onMoveUp={() => moveColumn(column.id, "up")}
560
+ onMoveDown={() => moveColumn(column.id, "down")}
561
+ isFirst={isFirst}
562
+ isLast={isLast}
563
+ copy={copy}
564
+ dropIndicatorPosition={dropIndicatorPosition}
565
+ />
566
+ );
567
+ };