Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions integrations/vite/src/components/Clickable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useState } from "react";

export type ClickableProps = { className?: string; id?: string };

export function Clickable({ className = "", id }: ClickableProps) {
const [counts, setCounts] = useState({
pointerDown: 0,
pointerUp: 0
});

const label = id ? `Clickable ${id}` : "Clickable";

return (
<pre
className={className}
onPointerDown={(event) => {
if (event.defaultPrevented) {
return;
}

setCounts({
pointerDown: counts.pointerDown + 1,
pointerUp: counts.pointerUp
});
}}
onPointerUp={(event) => {
if (event.defaultPrevented) {
return;
}

setCounts({
pointerDown: counts.pointerDown,
pointerUp: counts.pointerUp + 1
});
}}
>
<code>
{label} down:{counts.pointerDown} up:{counts.pointerUp}
</code>
</pre>
);
}
47 changes: 47 additions & 0 deletions integrations/vite/tests/pointer-interactions.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { calculateHitArea } from "./utils/calculateHitArea";
import { getCenterCoordinates } from "./utils/getCenterCoordinates";
import { goToUrl } from "./utils/goToUrl";
import { resizeHelper } from "./utils/pointer-interactions/resizeHelper";
import { Container } from "../src/components/Container";
import { Clickable } from "../src/components/Clickable";

test.describe("pointer interactions", () => {
for (const usePopUpWindow of [true, false]) {
Expand Down Expand Up @@ -74,6 +76,51 @@ test.describe("pointer interactions", () => {
await expect(mainPage.getByText('"left": 30')).toBeVisible();
});

// See github.com/bvaughn/react-resizable-panels/issues/594
test("should only call preventDefault for pointerup events that were handled by this library", async ({
page: mainPage
}) => {
const page = await goToUrl(
mainPage,
<Container className="relative">
<Group>
<Panel defaultSize="30%" id="left" minSize={50} />
<Separator />
<Panel id="right" minSize={50} />
</Group>
<Clickable className="bg-red-600 absolute left-0 top-0 p-2" />
</Container>,
{ usePopUpWindow }
);

const clickable = page.getByText("Clickable");
const clickableBox = (await clickable.boundingBox())!;

// A handled "pointerdown" event should also prevent the corresponding "pointerup" event

const separator = page.getByRole("separator");
const separatorBox = (await separator.boundingBox())!;

await page.mouse.move(
separatorBox.x,
separatorBox.y + separatorBox.height
);
await page.mouse.down();
await page.mouse.move(clickableBox.x, clickableBox.y);
await page.mouse.up();

await expect(page.getByText("Clickable down:0 up:0")).toBeVisible();

// An unhandled "pointerdown" event should not prevent the corresponding "pointerup" event

await page.mouse.move(1000, 0);
await page.mouse.down();
await page.mouse.move(clickableBox.x, clickableBox.y);
await page.mouse.up();

await expect(page.getByText("Clickable down:0 up:1")).toBeVisible();
});

test("drag panel boundary to resize group", async ({
page: mainPage
}) => {
Expand Down
16 changes: 13 additions & 3 deletions integrations/vite/tests/utils/serializer/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import type {
PanelProps,
SeparatorProps
} from "react-resizable-panels";
import { Clickable } from "../../../src/components/Clickable";
import { Container } from "../../../src/components/Container";
import { DisplayModeToggle } from "../../../src/components/DisplayModeToggle";
import { Group } from "../../../src/components/Group";
import { Panel } from "../../../src/components/Panel";
import { PopupWindow } from "../../../src/components/PopupWindow";
import { Separator } from "../../../src/components/Separator";
import type {
EncodedClickableElement,
EncodedContainerElement,
EncodedDisplayModeToggleElement,
EncodedElement,
Expand Down Expand Up @@ -47,6 +49,10 @@ function decodeChildren(
}

switch (current.type) {
case "Clickable": {
elements.push(decodeClickable(current));
break;
}
case "Container": {
elements.push(decodeContainer(current, config));
break;
Expand Down Expand Up @@ -84,6 +90,13 @@ function decodeChildren(
return elements;
}

function decodeClickable(json: EncodedClickableElement): ReactElement<unknown> {
return createElement(Clickable, {
key: ++key,
...json.props
});
}

function decodeContainer(
json: EncodedContainerElement,
config: Config
Expand All @@ -93,7 +106,6 @@ function decodeContainer(
return createElement(Container, {
key: ++key,
...props,
...config.panelProps,
children: children ? decodeChildren(children, config) : undefined
});
}
Expand All @@ -107,7 +119,6 @@ function decodeDisplayModeToggle(
return createElement(DisplayModeToggle, {
key: ++key,
...props,
...config.panelProps,
children: children ? decodeChildren(children, config) : undefined
});
}
Expand Down Expand Up @@ -149,7 +160,6 @@ function decodePopupWindow(
return createElement(PopupWindow, {
key: ++key,
...props,
...config.panelProps,
children: children ? decodeChildren(children, config) : undefined
});
}
Expand Down
18 changes: 18 additions & 0 deletions integrations/vite/tests/utils/serializer/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
type PanelProps,
type SeparatorProps
} from "react-resizable-panels";
import {
Clickable,
type ClickableProps
} from "../../../src/components/Clickable";
import {
Container,
type ContainerProps
Expand All @@ -20,6 +24,7 @@ import {
type PopupWindowProps
} from "../../../src/components/PopupWindow";
import type {
EncodedClickableElement,
EncodedContainerElement,
EncodedDisplayModeToggleElement,
EncodedElement,
Expand Down Expand Up @@ -47,6 +52,10 @@ function encodeChildren(children: ReactElement<unknown>[]): EncodedElement[] {
}

switch (current.type) {
case Clickable: {
elements.push(encodeClickable(current as ReactElement<ClickableProps>));
break;
}
case Container: {
elements.push(encodeContainer(current as ReactElement<ContainerProps>));
break;
Expand Down Expand Up @@ -93,6 +102,15 @@ function encodeChildren(children: ReactElement<unknown>[]): EncodedElement[] {
return elements;
}

function encodeClickable(
element: ReactElement<ClickableProps>
): EncodedClickableElement {
return {
props: element.props,
type: "Clickable"
};
}

function encodeContainer(
element: ReactElement<ContainerProps>
): EncodedContainerElement {
Expand Down
7 changes: 7 additions & 0 deletions integrations/vite/tests/utils/serializer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ import type {
import type { ContainerProps } from "../../../src/components/Container";
import type { DisplayModeToggleProps } from "../../../src/components/DisplayModeToggle";
import type { PopupWindowProps } from "../../../src/components/PopupWindow";
import type { ClickableProps } from "../../../src/components/Clickable";

type EncodedElementWithChildren<Props extends object = object> = Omit<
Props,
"children"
> & { children?: EncodedElement[] | undefined };

export interface EncodedClickableElement {
props: EncodedElementWithChildren<ClickableProps>;
type: "Clickable";
}

export interface EncodedContainerElement {
props: EncodedElementWithChildren<ContainerProps>;
type: "Container";
Expand Down Expand Up @@ -53,6 +59,7 @@ export interface EncodedTextElement {
}

export type EncodedElement =
| EncodedClickableElement
| EncodedContainerElement
| EncodedDisplayModeToggleElement
| EncodedGroupElement
Expand Down
Loading