Skip to content

Commit

Permalink
feat(list): add newIndex and oldIndex event details to calciteListOrd…
Browse files Browse the repository at this point in the history
…erChange event (#7874)

**Related Issue:** #7875

## Summary

- Add more useful event details to `calciteListOrderChange` event
- Adds `oldIndex` and `newIndex` properties to the event detail
- Adds test
  • Loading branch information
driskull authored Sep 27, 2023
1 parent 3dcceb0 commit 0d5cc20
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 25 deletions.
43 changes: 33 additions & 10 deletions packages/calcite-components/src/components/list/list.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { debounceTimeout } from "./resources";
import { CSS } from "../list-item/resources";
import { DEBOUNCE_TIMEOUT as FILTER_DEBOUNCE_TIMEOUT } from "../filter/resources";
import { GlobalTestProps, dragAndDrop, isElementFocused } from "../../tests/utils";
import { DragDetail } from "../../utils/sortableComponent";

const placeholder = placeholderImage({
width: 140,
Expand Down Expand Up @@ -474,16 +475,23 @@ describe("calcite-list", () => {

type TestWindow = GlobalTestProps<{
calledTimes: number;
newIndex: number;
oldIndex: number;
}>;

it("works using a mouse", async () => {
const page = await createSimpleList();

// Workaround for page.spyOnEvent() failing due to drag event payload being serialized and there being circular JSON structures from the payload elements. See: https://github.com/Esri/calcite-design-system/issues/7643
await page.$eval("calcite-list", (list: HTMLCalciteListElement) => {
(window as TestWindow).calledTimes = 0;
list.addEventListener("calciteListOrderChange", () => {
(window as TestWindow).calledTimes++;
const testWindow = window as TestWindow;
testWindow.calledTimes = 0;
testWindow.newIndex = -1;
testWindow.oldIndex = -1;
list.addEventListener("calciteListOrderChange", (event: CustomEvent<DragDetail>) => {
testWindow.calledTimes++;
testWindow.newIndex = event?.detail?.newIndex;
testWindow.oldIndex = event?.detail?.oldIndex;
});
});

Expand All @@ -504,7 +512,14 @@ describe("calcite-list", () => {
expect(await second.getProperty("value")).toBe("one");
await page.waitForChanges();

expect(await page.evaluate(() => (window as TestWindow).calledTimes)).toBe(1);
const results = await page.evaluate(() => {
const testWindow = window as TestWindow;
return { calledTimes: testWindow.calledTimes, oldIndex: testWindow.oldIndex, newIndex: testWindow.newIndex };
});

expect(results.calledTimes).toBe(1);
expect(results.oldIndex).toBe(0);
expect(results.newIndex).toBe(1);
});

it("supports dragging items between lists", async () => {
Expand Down Expand Up @@ -536,11 +551,12 @@ describe("calcite-list", () => {

// Workaround for page.spyOnEvent() failing due to drag event payload being serialized and there being circular JSON structures from the payload elements. See: https://github.com/Esri/calcite-design-system/issues/7643
await page.evaluate(() => {
(window as TestWindow).calledTimes = 0;
const testWindow = window as TestWindow;
testWindow.calledTimes = 0;
const lists = document.querySelectorAll("calcite-list");
lists.forEach((list) =>
list.addEventListener("calciteListOrderChange", () => {
(window as TestWindow).calledTimes++;
testWindow.calledTimes++;
})
);
});
Expand Down Expand Up @@ -616,24 +632,31 @@ describe("calcite-list", () => {

let totalMoves = 0;

const eventSpy = await page.spyOnEvent("calciteListOrderChange");
// Workaround for page.spyOnEvent() failing due to drag event payload being serialized and there being circular JSON structures from the payload elements. See: https://github.com/Esri/calcite-design-system/issues/7643
await page.$eval("calcite-list", (list: HTMLCalciteListElement) => {
const testWindow = window as TestWindow;
testWindow.calledTimes = 0;
list.addEventListener("calciteListOrderChange", () => {
testWindow.calledTimes++;
});
});

async function assertKeyboardMove(
arrowKey: "ArrowDown" | "ArrowUp",
expectedValueOrder: string[]
): Promise<void> {
const calciteListOrderChangeEvent = page.waitForEvent("calciteListOrderChange");
await page.waitForChanges();
await page.keyboard.press(arrowKey);
await calciteListOrderChangeEvent;
const itemsAfter = await page.findAll("calcite-list-item");
expect(itemsAfter.length).toBe(3);

for (let i = 0; i < itemsAfter.length; i++) {
expect(await itemsAfter[i].getProperty("value")).toBe(expectedValueOrder[i]);
}

expect(eventSpy).toHaveReceivedEventTimes(++totalMoves);
const calledTimes = await page.evaluate(() => (window as TestWindow).calledTimes);

expect(calledTimes).toBe(++totalMoves);
}

await assertKeyboardMove("ArrowDown", ["two", "one", "three"]);
Expand Down
26 changes: 15 additions & 11 deletions packages/calcite-components/src/components/list/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -766,23 +766,25 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo
const sameParentItems = enabledListItems.filter((item) => item.parentElement === parentEl);

const lastIndex = sameParentItems.length - 1;
const startingIndex = sameParentItems.indexOf(sortItem);
const oldIndex = sameParentItems.indexOf(sortItem);
let appendInstead = false;
let buddyIndex: number;
let newIndex: number;

if (direction === "up") {
if (startingIndex === 0) {
if (oldIndex === 0) {
appendInstead = true;
newIndex = lastIndex;
} else {
buddyIndex = startingIndex - 1;
newIndex = oldIndex - 1;
}
} else {
if (startingIndex === lastIndex) {
buddyIndex = 0;
} else if (startingIndex === lastIndex - 1) {
if (oldIndex === lastIndex) {
newIndex = 0;
} else if (oldIndex === lastIndex - 1) {
appendInstead = true;
newIndex = lastIndex;
} else {
buddyIndex = startingIndex + 2;
newIndex = oldIndex + 2;
}
}

Expand All @@ -791,16 +793,18 @@ export class List implements InteractiveComponent, LoadableComponent, SortableCo
if (appendInstead) {
parentEl.appendChild(sortItem);
} else {
parentEl.insertBefore(sortItem, sameParentItems[buddyIndex]);
parentEl.insertBefore(sortItem, sameParentItems[newIndex]);
}

this.updateListItems();
this.connectObserver();

this.calciteListOrderChange.emit({
dragEl: sortItem,
fromEl: null,
toEl: null,
fromEl: parentEl,
toEl: parentEl,
newIndex,
oldIndex,
});

handle.setFocus().then(() => {
Expand Down
12 changes: 8 additions & 4 deletions packages/calcite-components/src/utils/sortableComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export interface DragDetail {
toEl: HTMLElement;
fromEl: HTMLElement;
dragEl: HTMLElement;
newIndex: number;
oldIndex: number;
}

export const CSS = {
Expand Down Expand Up @@ -93,10 +95,12 @@ export function connectSortableComponent(component: SortableComponent): void {
group: {
name: group,
...(!!component.canPull && {
pull: (to, from, dragEl) => component.canPull({ toEl: to.el, fromEl: from.el, dragEl }),
pull: (to, from, dragEl, { newIndex, oldIndex }) =>
component.canPull({ toEl: to.el, fromEl: from.el, dragEl, newIndex, oldIndex }),
}),
...(!!component.canPut && {
put: (to, from, dragEl) => component.canPut({ toEl: to.el, fromEl: from.el, dragEl }),
put: (to, from, dragEl, { newIndex, oldIndex }) =>
component.canPut({ toEl: to.el, fromEl: from.el, dragEl, newIndex, oldIndex }),
}),
},
}),
Expand All @@ -109,8 +113,8 @@ export function connectSortableComponent(component: SortableComponent): void {
dragState.active = false;
onDragEnd();
},
onSort: ({ from: fromEl, item: dragEl, to: toEl }) => {
component.onDragSort({ fromEl, dragEl, toEl });
onSort: ({ from: fromEl, item: dragEl, to: toEl, newIndex, oldIndex }) => {
component.onDragSort({ fromEl, dragEl, toEl, newIndex, oldIndex });
},
});
}
Expand Down

0 comments on commit 0d5cc20

Please sign in to comment.