@purpurds/table 8.6.0 → 8.8.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.
@@ -1,102 +1,12 @@
1
1
  import React from "react";
2
- import { fireEvent, render, screen } from "@testing-library/react";
2
+ import { render, screen } from "@testing-library/react";
3
3
  import userEvent from "@testing-library/user-event";
4
4
  import { axe } from "vitest-axe";
5
5
 
6
- import { TableColumnDragHandle, useDragHandle } from "./use-drag-handle.hook";
7
-
8
- // Test component to test the hook
9
- function TestDragHandleComponent() {
10
- const { mouseDownActive, handleMouseDown } = useDragHandle();
11
-
12
- return (
13
- <div>
14
- <span data-testid="mouse-down-state">{mouseDownActive ? "active" : "inactive"}</span>
15
- <button onClick={handleMouseDown} data-testid="trigger-button">
16
- Trigger Mouse Down
17
- </button>
18
- </div>
19
- );
20
- }
21
-
22
- describe("useDragHandle Hook", () => {
23
- beforeEach(() => {
24
- // Clean up any event listeners
25
- vi.clearAllMocks();
26
- });
27
-
28
- afterEach(() => {
29
- // Clean up global event listeners
30
- const events = ["mouseup"];
31
- events.forEach((event) => {
32
- window.removeEventListener(event, () => {});
33
- });
34
- });
35
-
36
- it("should initialize with mouseDownActive as false", () => {
37
- render(<TestDragHandleComponent />);
38
-
39
- const stateElement = screen.getByTestId("mouse-down-state");
40
- expect(stateElement).toHaveTextContent("inactive");
41
- });
42
-
43
- it("should set mouseDownActive to true when handleMouseDown is called", async () => {
44
- const user = userEvent.setup();
45
- render(<TestDragHandleComponent />);
46
-
47
- const triggerButton = screen.getByTestId("trigger-button");
48
- const stateElement = screen.getByTestId("mouse-down-state");
49
-
50
- expect(stateElement).toHaveTextContent("inactive");
51
-
52
- await user.click(triggerButton);
53
-
54
- expect(stateElement).toHaveTextContent("active");
55
- });
56
-
57
- it("should reset mouseDownActive to false when mouse up event occurs", async () => {
58
- const user = userEvent.setup();
59
- render(<TestDragHandleComponent />);
60
-
61
- const triggerButton = screen.getByTestId("trigger-button");
62
- const stateElement = screen.getByTestId("mouse-down-state");
63
-
64
- // Trigger mouse down
65
- await user.click(triggerButton);
66
- expect(stateElement).toHaveTextContent("active");
67
-
68
- // Simulate mouse up on window
69
- fireEvent.mouseUp(window);
70
-
71
- expect(stateElement).toHaveTextContent("inactive");
72
- });
73
-
74
- it("should add and remove mouseup event listener correctly", async () => {
75
- const addEventListenerSpy = vi.spyOn(window, "addEventListener");
76
- const removeEventListenerSpy = vi.spyOn(window, "removeEventListener");
77
-
78
- const user = userEvent.setup();
79
- render(<TestDragHandleComponent />);
80
-
81
- const triggerButton = screen.getByTestId("trigger-button");
82
-
83
- await user.click(triggerButton);
84
-
85
- expect(addEventListenerSpy).toHaveBeenCalledWith("mouseup", expect.any(Function), {
86
- once: true,
87
- });
88
-
89
- // Trigger mouseup to remove listener
90
- fireEvent.mouseUp(window);
91
-
92
- addEventListenerSpy.mockRestore();
93
- removeEventListenerSpy.mockRestore();
94
- });
95
- });
6
+ import { TableColumnDragHandle } from "./use-drag-handle.hook";
96
7
 
97
8
  describe("TableColumnDragHandle Component", () => {
98
9
  const defaultProps = {
99
- onMouseDown: vi.fn(),
100
10
  overlayActive: false,
101
11
  isFirstColumn: false,
102
12
  isLastColumn: false,
@@ -197,81 +107,31 @@ describe("TableColumnDragHandle Component", () => {
197
107
  });
198
108
 
199
109
  describe("Event Handling", () => {
200
- it("should call onMouseDown when clicked", async () => {
201
- const user = userEvent.setup();
202
- const onMouseDownMock = vi.fn();
203
-
204
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
205
-
206
- const dragHandle = screen.getByRole("button");
207
- await user.click(dragHandle);
208
-
209
- expect(onMouseDownMock).toHaveBeenCalledTimes(1);
210
- });
211
-
212
- it("should call onMouseDown when mouse down event is triggered", () => {
213
- const onMouseDownMock = vi.fn();
214
-
215
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
216
-
217
- const dragHandle = screen.getByRole("button");
218
- fireEvent.mouseDown(dragHandle);
110
+ it("should pass through dragListeners props", () => {
111
+ const mockListener = vi.fn();
112
+ const dragListeners = {
113
+ onMouseDown: mockListener,
114
+ onTouchStart: mockListener,
115
+ };
219
116
 
220
- expect(onMouseDownMock).toHaveBeenCalledTimes(1);
221
- });
222
-
223
- it("should call onMouseDown when Enter key is pressed", async () => {
224
- const user = userEvent.setup();
225
- const onMouseDownMock = vi.fn();
226
-
227
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
228
-
229
- const dragHandle = screen.getByRole("button");
230
- dragHandle.focus();
231
- await user.keyboard("{Enter}");
232
-
233
- expect(onMouseDownMock).toHaveBeenCalledTimes(1);
234
- });
235
-
236
- it("should call onMouseDown when Space key is pressed", async () => {
237
- const user = userEvent.setup();
238
- const onMouseDownMock = vi.fn();
239
-
240
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
117
+ render(<TableColumnDragHandle {...defaultProps} {...dragListeners} />);
241
118
 
242
119
  const dragHandle = screen.getByRole("button");
243
- dragHandle.focus();
244
- await user.keyboard(" ");
245
-
246
- expect(onMouseDownMock).toHaveBeenCalledTimes(1);
247
- });
248
-
249
- it("should not call onMouseDown for other key presses", async () => {
250
- const user = userEvent.setup();
251
- const onMouseDownMock = vi.fn();
252
120
 
253
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
254
-
255
- const dragHandle = screen.getByRole("button");
256
- dragHandle.focus();
257
- await user.keyboard("{Escape}");
258
-
259
- expect(onMouseDownMock).not.toHaveBeenCalled();
121
+ // Verify the listeners are attached
122
+ expect(dragHandle).toHaveAttribute("role", "button");
260
123
  });
261
124
 
262
- it("should handle multiple rapid clicks", async () => {
263
- const user = userEvent.setup();
264
- const onMouseDownMock = vi.fn();
265
-
266
- render(<TableColumnDragHandle {...defaultProps} onMouseDown={onMouseDownMock} />);
267
-
268
- const dragHandle = screen.getByRole("button");
269
-
270
- await user.click(dragHandle);
271
- await user.click(dragHandle);
272
- await user.click(dragHandle);
273
-
274
- expect(onMouseDownMock).toHaveBeenCalledTimes(3);
125
+ it("should not throw when receiving additional props", () => {
126
+ expect(() => {
127
+ render(
128
+ <TableColumnDragHandle
129
+ {...defaultProps}
130
+ data-testid="custom-test-id"
131
+ customProp="value"
132
+ />
133
+ );
134
+ }).not.toThrow();
275
135
  });
276
136
  });
277
137
 
@@ -337,19 +197,6 @@ describe("TableColumnDragHandle Component", () => {
337
197
  });
338
198
 
339
199
  describe("Props Validation", () => {
340
- it("should handle undefined onMouseDown gracefully", () => {
341
- expect(() => {
342
- render(
343
- <TableColumnDragHandle
344
- {...defaultProps}
345
- onMouseDown={
346
- undefined as unknown as Parameters<typeof TableColumnDragHandle>[0]["onMouseDown"]
347
- }
348
- />
349
- );
350
- }).not.toThrow();
351
- });
352
-
353
200
  it("should handle empty aria label", () => {
354
201
  render(<TableColumnDragHandle {...defaultProps} columnDragAriaLabel="" />);
355
202
 
@@ -1,83 +1,44 @@
1
- import {
2
- closestCorners,
3
- type DroppableContainer,
4
- getFirstCollision,
5
- KeyboardCode,
6
- type KeyboardCoordinateGetter,
7
- } from "@dnd-kit/core";
1
+ import { KeyboardCode, type KeyboardCoordinateGetter } from "@dnd-kit/core";
8
2
 
9
3
  /**
10
- * Enhanced keyboard coordinate handler that better handles columns of different widths
11
- * by positioning the dragged column appropriately within target columns
4
+ * Simple keyboard coordinate handler that moves the drag overlay
5
+ * left or right incrementally and lets collision detection determine
6
+ * which column we're over.
12
7
  */
13
8
  export const enhancedColumnKeyboardCoordinates: KeyboardCoordinateGetter = (
14
9
  event,
15
- { context: { active, collisionRect, droppableRects, droppableContainers, over } }
10
+ { currentCoordinates, context: { active, droppableRects } }
16
11
  ) => {
17
- if (!active || !collisionRect) {
12
+ if (!active || !currentCoordinates) {
18
13
  return;
19
14
  }
20
15
 
21
- // Only handle left/right movements for column dragging
22
- if (event.code === KeyboardCode.Right || event.code === KeyboardCode.Left) {
23
- event.preventDefault();
24
-
25
- const filteredContainers: DroppableContainer[] = [];
26
-
27
- droppableContainers.getEnabled().forEach((container) => {
28
- if (container?.disabled) return;
29
-
30
- const rect = droppableRects.get(container.id);
31
- if (!rect) return;
32
-
33
- // Filter based on direction
34
- if (event.code === KeyboardCode.Right && collisionRect.left < rect.left) {
35
- filteredContainers.push(container);
36
- } else if (event.code === KeyboardCode.Left && collisionRect.left > rect.left) {
37
- filteredContainers.push(container);
38
- }
39
- });
40
-
41
- // Sort containers by distance (nearest first) for left movement
42
- if (event.code === KeyboardCode.Left && filteredContainers.length > 0) {
43
- filteredContainers.sort((a, b) => {
44
- const rectA = droppableRects.get(a.id);
45
- const rectB = droppableRects.get(b.id);
46
- if (!rectA || !rectB) return 0;
47
-
48
- // Sort by closest to furthest from the current position (for left movement)
49
- return rectB.left - rectA.left;
50
- });
51
- }
16
+ // Only handle left/right movements
17
+ if (event.code !== KeyboardCode.Right && event.code !== KeyboardCode.Left) {
18
+ return;
19
+ }
52
20
 
53
- // Find closest target
54
- const collisions = closestCorners({
55
- active,
56
- collisionRect,
57
- droppableRects,
58
- droppableContainers: filteredContainers,
59
- pointerCoordinates: null,
60
- });
21
+ event.preventDefault();
61
22
 
62
- let targetId = getFirstCollision(collisions, "id");
23
+ // Get the active column's width to determine appropriate step size
24
+ const activeRect = droppableRects.get(active.id);
25
+ if (!activeRect) {
26
+ return;
27
+ }
63
28
 
64
- // Get second collision if first is current "over" element
65
- if (targetId === over?.id && collisions.length > 1) {
66
- targetId = collisions[1].id;
67
- }
29
+ // Move by half the width of the active column or max 100px
30
+ const stepSize = Math.min(activeRect.width * 0.5, 100);
68
31
 
69
- if (targetId) {
70
- const targetRect = droppableRects.get(targetId);
32
+ let newX: number;
71
33
 
72
- if (targetRect) {
73
- return {
74
- x: targetRect.left + targetRect.width * 0.35,
75
- y: targetRect.top + targetRect.height / 2,
76
- };
77
- }
78
- }
34
+ if (event.code === KeyboardCode.Right) {
35
+ newX = currentCoordinates.x + stepSize;
36
+ } else {
37
+ newX = currentCoordinates.x - stepSize;
79
38
  }
80
39
 
81
- // For other keys, we don't handle them
82
- return;
40
+ return {
41
+ x: newX,
42
+ y: currentCoordinates.y,
43
+ };
83
44
  };