Skip to content

Commit

Permalink
fix: Fix drag handle focus after item acquisition (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-kot authored Aug 12, 2024
1 parent 66411c4 commit 430ecbb
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 1 deletion.
35 changes: 34 additions & 1 deletion src/board/__tests__/board-acquisition.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { useState } from "react";
import { act, render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest";

import { Board } from "../../../lib/components";
import { Board, BoardProps } from "../../../lib/components";
import { mockController } from "../../../lib/components/internal/dnd-controller/__mocks__/controller";
import { DragAndDropData } from "../../../lib/components/internal/dnd-controller/controller";
import { Coordinates } from "../../../lib/components/internal/utils/coordinates";
import createWrapper from "../../../lib/components/test-utils/dom";
import { defaultProps } from "./utils";

vi.mock("../../../lib/components/internal/dnd-controller/controller");
Expand Down Expand Up @@ -38,3 +40,34 @@ test("renders acquired item", () => {
act(() => mockController.discard());
expect(screen.queryByTestId("acquired-item")).toBeNull();
});

function StatefulBoard(props: BoardProps<{ title: string }>) {
const [items, setItems] = useState(props.items);
return <Board {...props} items={items} onItemsChange={({ detail }) => setItems(detail.items)} />;
}

test("focuses on acquired item's drag handle upon submission", () => {
render(<StatefulBoard {...defaultProps} />);
const draggableItem = { id: "test", data: { title: "Test item" }, definition: {} };

act(() =>
mockController.start({
interactionType: "keyboard",
operation: "insert",
draggableItem,
collisionRect: { top: 0, bottom: 0, left: 0, right: 0 },
coordinates: new Coordinates({ x: 0, y: 0 }),
} as DragAndDropData),
);

act(() =>
mockController.acquire({
droppableId: "awsui-placeholder-1-0",
draggableItem,
renderAcquiredItem: () => <div></div>,
}),
);

act(() => mockController.submit());
expect(createWrapper().findBoard()!.findItemById("test")!.findDragHandle().getElement()).toHaveFocus();
});
12 changes: 12 additions & 0 deletions src/board/internal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { ReactNode, useEffect, useRef } from "react";
import { usePrevious } from "@dnd-kit/utilities";
import clsx from "clsx";

import { getIsRtl } from "@cloudscape-design/component-toolkit/internal";
Expand Down Expand Up @@ -113,6 +114,17 @@ export function InternalBoard<D>({
return () => clearTimeout(timeoutId);
}, [removeTransition, items, onItemsChange]);

// When item is inserting with the keyboard it keeps rendering by the palette and upon submission
// it starts rendering by the board. This transitions might lead to the focus being lost from the item's drag handle.
// The below code refocuses the drag handle when detecting the acquired item is no longer used.
const acquiredItemId = usePrevious(acquiredItem?.id);
const previousAcquiredItemElement = usePrevious(acquiredItemElement);
useEffect(() => {
if (acquiredItemId && previousAcquiredItemElement && !acquiredItemElement) {
itemContainerRef.current[acquiredItemId]?.focusDragHandle();
}
}, [acquiredItemId, previousAcquiredItemElement, acquiredItemElement]);

const rows = selectTransitionRows(transitionState) || itemsLayout.rows;
const placeholdersLayout = createPlaceholdersLayout(rows, itemsLayout.columns);

Expand Down

0 comments on commit 430ecbb

Please sign in to comment.