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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ For most cases, it is recommended to use the <code>onLayoutChanged</code> callba
<td><p>Called after the Group&#39;s layout has been changed.</p>
<p>ℹ️ For layout changes caused by pointer events, this method is not called until the pointer has been released.
This method is recommended when saving layouts to some storage api.</p>
<p>The second argument is a <code>meta</code> object whose <code>isUserInteraction</code> field is
<code>true</code> when the change was caused by the user directly manipulating a
separator — releasing a pointer drag or pressing a resize key (arrow keys,
Home/End, Enter). It is <code>false</code> for every other source (programmatic
<code>setLayout</code> and other imperative API calls, constraint recompute,
default-size change, initial mount), because the library cannot attribute
the caller&#39;s intent there. See #716.</p>
</td>
</tr>
<tr>
Expand Down
204 changes: 132 additions & 72 deletions lib/components/group/Group.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ describe("Group", () => {
groupRef: RefObject<GroupImperativeHandle | null>;
panelRef: RefObject<PanelImperativeHandle | null>;
}) => Promise<void>,
expectedLayout: Layout
expectedLayout: Layout,
// `true` when the callback simulates a direct separator manipulation —
// a pointer drag or a keyboard resize (see #716); `false` for imperative
// API / mount which fall under the "library-driven" bucket of the flag.
expectedIsUserInteraction: boolean
) {
setElementBoundsFunction((element) => {
switch (element.id) {
Expand Down Expand Up @@ -133,15 +137,20 @@ describe("Group", () => {
);

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenLastCalledWith({
left: 50,
right: 50
});
expect(onLayoutChanged).toHaveBeenLastCalledWith(
{
left: 50,
right: 50
},
{ isUserInteraction: false }
);

await callback({ container, groupRef, panelRef });

expect(onLayoutChanged).toHaveBeenCalledTimes(2);
expect(onLayoutChanged).toHaveBeenLastCalledWith(expectedLayout);
expect(onLayoutChanged).toHaveBeenLastCalledWith(expectedLayout, {
isUserInteraction: expectedIsUserInteraction
});

rerender(
<Group groupRef={groupRef} onLayoutChanged={onLayoutChanged}>
Expand All @@ -150,7 +159,10 @@ describe("Group", () => {
);

expect(onLayoutChanged).toHaveBeenCalledTimes(3);
expect(onLayoutChanged).toHaveBeenLastCalledWith({ right: 100 });
expect(onLayoutChanged).toHaveBeenLastCalledWith(
{ right: 100 },
{ isUserInteraction: false }
);

rerender(
<Group groupRef={groupRef} onLayoutChanged={onLayoutChanged}>
Expand All @@ -161,7 +173,9 @@ describe("Group", () => {
);

expect(onLayoutChanged).toHaveBeenCalledTimes(4);
expect(onLayoutChanged).toHaveBeenLastCalledWith(expectedLayout);
expect(onLayoutChanged).toHaveBeenLastCalledWith(expectedLayout, {
isUserInteraction: false
});
}

test("should update when resized via pointer", async () => {
Expand All @@ -172,7 +186,8 @@ describe("Group", () => {
{
left: 60,
right: 40
}
},
true
);
});

Expand All @@ -185,7 +200,8 @@ describe("Group", () => {
{
left: 55,
right: 45
}
},
true
);
});

Expand All @@ -200,7 +216,8 @@ describe("Group", () => {
{
left: 75,
right: 25
}
},
false
);
});

Expand All @@ -212,7 +229,8 @@ describe("Group", () => {
{
left: 35,
right: 65
}
},
false
);
});
});
Expand Down Expand Up @@ -264,10 +282,13 @@ describe("Group", () => {
);

expect(onLayoutChanged).toBeCalledTimes(1);
expect(onLayoutChanged).toHaveBeenLastCalledWith({
left: 25,
right: 75
});
expect(onLayoutChanged).toHaveBeenLastCalledWith(
{
left: 25,
right: 75
},
{ isUserInteraction: false }
);
expect(groupRef.current?.getLayout()).toEqual({
left: 25,
right: 75
Expand Down Expand Up @@ -310,10 +331,13 @@ describe("Group", () => {
);

expect(onLayoutChanged).toBeCalledTimes(1);
expect(onLayoutChanged).toHaveBeenLastCalledWith({
left: 25,
right: 75
});
expect(onLayoutChanged).toHaveBeenLastCalledWith(
{
left: 25,
right: 75
},
{ isUserInteraction: false }
);
expect(groupRef.current?.getLayout()).toEqual({
left: 25,
right: 75
Expand All @@ -328,10 +352,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toBeCalledTimes(2);
expect(onLayoutChanged).toHaveBeenLastCalledWith({
left: 20,
right: 80
});
expect(onLayoutChanged).toHaveBeenLastCalledWith(
{
left: 20,
right: 80
},
{ isUserInteraction: false }
);
expect(groupRef.current?.getLayout()).toEqual({
left: 20,
right: 80
Expand Down Expand Up @@ -429,19 +456,25 @@ describe("Group", () => {
);

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
left: 60,
right: 40
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
left: 60,
right: 40
},
{ isUserInteraction: false }
);

// Simulate a drag from the draggable element to the target area
await moveSeparator(10);

expect(onLayoutChanged).toHaveBeenCalledTimes(2);
expect(onLayoutChanged).toHaveBeenCalledWith({
left: 70,
right: 30
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
left: 70,
right: 30
},
{ isUserInteraction: true }
);
});

test("three panel vertical group", async () => {
Expand Down Expand Up @@ -489,21 +522,27 @@ describe("Group", () => {
);

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
bottom: 50,
middle: 30,
top: 20
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
bottom: 50,
middle: 30,
top: 20
},
{ isUserInteraction: false }
);

// Simulate a drag from the draggable element to the target area
await moveSeparator(15, "top-separator");

expect(onLayoutChanged).toHaveBeenCalledTimes(2);
expect(onLayoutChanged).toHaveBeenCalledWith({
bottom: 50,
middle: 20,
top: 30
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
bottom: 50,
middle: 20,
top: 30
},
{ isUserInteraction: true }
);
});
});

Expand Down Expand Up @@ -706,10 +745,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 50,
b: 50
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 50,
b: 50
},
{ isUserInteraction: false }
);

rerender(
<Group
Expand Down Expand Up @@ -746,10 +788,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 40,
b: 60
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 40,
b: 60
},
{ isUserInteraction: false }
);

rerender(
<Group
Expand Down Expand Up @@ -787,10 +832,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 50,
b: 50
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 50,
b: 50
},
{ isUserInteraction: false }
);

rerender(
<Group
Expand All @@ -813,12 +861,15 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(2);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 25,
b: 25,
c: 25,
d: 25
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 25,
b: 25,
c: 25,
d: 25
},
{ isUserInteraction: false }
);
});

test("should be called once per layout change", async () => {
Expand Down Expand Up @@ -857,10 +908,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 50,
c: 50
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 50,
c: 50
},
{ isUserInteraction: false }
);

onLayoutChange.mockReset();
onLayoutChanged.mockReset();
Expand All @@ -875,10 +929,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 75,
c: 25
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 75,
c: 25
},
{ isUserInteraction: true }
);

onLayoutChange.mockReset();
onLayoutChanged.mockReset();
Expand Down Expand Up @@ -919,10 +976,13 @@ describe("Group", () => {
});

expect(onLayoutChanged).toHaveBeenCalledTimes(1);
expect(onLayoutChanged).toHaveBeenCalledWith({
a: 25,
b: 75
});
expect(onLayoutChanged).toHaveBeenCalledWith(
{
a: 25,
b: 75
},
{ isUserInteraction: false }
);

rerender(
<Group
Expand Down
Loading
Loading