Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
feat(value-list): allow dragging items between lists (#1059)
Browse files Browse the repository at this point in the history
* tidy up value-list demos
* add dnd test util
* unskip existing dnd tests

#1056
  • Loading branch information
jcfranco committed Aug 25, 2020
1 parent 1308789 commit 1c35a0d
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 93 deletions.
44 changes: 13 additions & 31 deletions src/components/calcite-sortable-list/calcite-sortable-list.e2e.ts
@@ -1,5 +1,6 @@
import { E2EPage, newE2EPage } from "@stencil/core/testing";
import { E2EPage } from "@stencil/core/testing";
import { accessible, hidden, renders } from "../../tests/commonTests";
import { dragAndDrop, setUpPage } from "../../tests/utils";

describe("calcite-sortable-list", () => {
it("renders", async () => renders("calcite-sortable-list"));
Expand All @@ -11,41 +12,22 @@ describe("calcite-sortable-list", () => {
describe("drag and drop", () => {
let page: E2EPage;
beforeEach(async () => {
page = await newE2EPage();
await page.setContent(`<calcite-sortable-list>
page = await setUpPage(
`<calcite-sortable-list>
<div id="one"><calcite-handle></calcite-handle>1</div>
<div id="two"><calcite-handle></calcite-handle>2</div>
<div id="three"><calcite-handle></calcite-handle>3</div>
</calcite-sortable-list>`);
await page.addScriptTag({
url: "https://unpkg.com/@esri/calcite-components@1.0.0-beta.16/dist/calcite/calcite.esm.js",
type: "module"
});
</calcite-sortable-list>`,
{ withPeerDependencies: true }
);
});
it.skip("works using a mouse", async () => {
// TODO: remove skip once https://github.com/GoogleChrome/puppeteer/issues/1376 addressed
const itemBoundingBox = await page.evaluate(() => {
const { left, top, width, height } = document.querySelector(`#one`).getBoundingClientRect();
return { left, top, width, height };
});
const handleBoundingBox = await page.evaluate(() => {
const { left, top, width, height } = document
.querySelector(`#one calcite-handle`)
.shadowRoot.querySelector(`button`)
.getBoundingClientRect();
return { left, top, width, height };
});
const xCenter = handleBoundingBox.left + handleBoundingBox.width / 2;
const yCenter = handleBoundingBox.top + handleBoundingBox.height / 2;
await page.mouse.move(xCenter, yCenter);
await page.mouse.down();
await page.mouse.move(xCenter, yCenter + itemBoundingBox.height + 2);
await page.mouse.up();

// position in DOM of first and second item should be flipped
const itemsAfter = await page.findAll("div");
expect(await itemsAfter[0].getProperty("id")).toBe("two");
expect(await itemsAfter[1].getProperty("id")).toBe("one");
it("works using a mouse", async () => {
await dragAndDrop(page, `#one calcite-handle`, `#two calcite-handle`);

const [first, second] = await page.findAll("div");
expect(await first.getProperty("id")).toBe("two");
expect(await second.getProperty("id")).toBe("one");
});

it("works using a keyboard", async () => {
Expand Down
140 changes: 102 additions & 38 deletions src/components/calcite-value-list/calcite-value-list.e2e.ts
Expand Up @@ -7,6 +7,7 @@ import {
disabledStates,
keyboardNavigation
} from "../calcite-pick-list/shared-list-tests";
import { dragAndDrop } from "../../tests/utils";

describe("calcite-value-list", () => {
it("renders", async () => renders("calcite-value-list"));
Expand All @@ -24,20 +25,22 @@ describe("calcite-value-list", () => {

describe("icon logic", () => {
it("should be 'grip' when in `configuration` mode drag and drop is enabled ", async () => {
const page = await newE2EPage();
await page.setContent(`<calcite-value-list drag-enabled>
const page = await newE2EPage({
html: `<calcite-value-list drag-enabled>
<calcite-value-list-item value="one"></calcite-value-list-item>
</calcite-value-list>`);
</calcite-value-list>`
});

const item = await page.find("calcite-value-list-item");
const icon = await item.getProperty("icon");
expect(icon).toBe(ICON_TYPES.grip);
});
it("should be null when drag and drop is disabled", async () => {
const page = await newE2EPage();
await page.setContent(`<calcite-value-list>
const page = await newE2EPage({
html: `<calcite-value-list>
<calcite-value-list-item value="one"></calcite-value-list-item>
</calcite-value-list>`);
</calcite-value-list>`
});

const item = await page.find("calcite-value-list-item");
const icon = await item.getProperty("icon");
Expand All @@ -54,45 +57,39 @@ describe("calcite-value-list", () => {
});

describe("drag and drop", () => {
let page: E2EPage;
beforeEach(async () => {
page = await newE2EPage();
await page.setContent(`<calcite-value-list multiple drag-enabled>
async function createSimpleValueList(): Promise<E2EPage> {
return newE2EPage({
html: `<calcite-value-list drag-enabled>
<calcite-value-list-item value="one" text-label="One"></calcite-value-list-item>
<calcite-value-list-item value="two" text-label="Two"></calcite-value-list-item>
<calcite-value-list-item value="three" text-label="Three"></calcite-value-list-item>
</calcite-value-list>`);
});
it.skip("works using a mouse", async () => {
// TODO: remove skip once https://github.com/GoogleChrome/puppeteer/issues/1376 addressed
const itemBoundingBox = await page.evaluate(() => {
const { left, top, width, height } = document
.querySelector(`calcite-value-list-item[value="one"]`)
.getBoundingClientRect();
return { left, top, width, height };
</calcite-value-list>`
});
const handleBoundingBoxes = await page.evaluate((CSS) => {
const { left, top, width, height } = document
.querySelector(`calcite-value-list-item[value="one"]`)
.shadowRoot.querySelector(`calcite-pick-list-item`)
.shadowRoot.querySelector(`.${CSS.handle}`)
.getBoundingClientRect();
return { left, top, width, height };
}, CSS);
const xCenter = handleBoundingBoxes.left + handleBoundingBoxes.width / 2;
const yCenter = handleBoundingBoxes.top + handleBoundingBoxes.height / 2;
await page.mouse.move(xCenter, yCenter);
await page.mouse.down();
await page.mouse.move(xCenter, yCenter + itemBoundingBox.height + 2);
await page.mouse.up();

// position in DOM of first and second item should be flipped
const itemsAfter = await page.findAll("calcite-value-list-item");
expect(await itemsAfter[0].getProperty("value")).toBe("two");
expect(await itemsAfter[1].getProperty("value")).toBe("one");
}

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

await dragAndDrop(
page,
{
host: `calcite-value-list-item[value="one"]`,
shadow: `.${CSS.handle}`
},
{
host: `calcite-value-list-item[value="two"]`,
shadow: `.${CSS.handle}`
}
);

const [first, second] = await page.findAll("calcite-value-list-item");
expect(await first.getProperty("value")).toBe("two");
expect(await second.getProperty("value")).toBe("one");
});

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

await page.keyboard.press("Tab");
await page.keyboard.press("Space");
await page.waitForChanges();
Expand All @@ -116,5 +113,72 @@ describe("calcite-value-list", () => {
await assertKeyboardMove("up", ["two", "one", "three"]);
await assertKeyboardMove("up", ["one", "two", "three"]);
});

it("supports dragging items between lists", async () => {
const page = await newE2EPage({
html: `
<calcite-value-list id="first-letters" drag-enabled group="letters">
<calcite-value-list-item value="a" text-label="A"></calcite-value-list-item>
<calcite-value-list-item value="b" text-label="B"></calcite-value-list-item>
</calcite-value-list>
<calcite-value-list id="numbers" drag-enabled group="numbers">
<calcite-value-list-item value="1" text-label="One"></calcite-value-list-item>
<calcite-value-list-item value="2" text-label="Two"></calcite-value-list-item>
</calcite-value-list>
<calcite-value-list id="no-group" drag-enabled>
<calcite-value-list-item value="no-group" text-label="No group"></calcite-value-list-item>
</calcite-value-list>
<calcite-value-list id="second-letters" drag-enabled group="letters">
<calcite-value-list-item value="c" text-label="C"></calcite-value-list-item>
<calcite-value-list-item value="d" text-label="D"></calcite-value-list-item>
<calcite-value-list-item value="e" text-label="E"></calcite-value-list-item>
<calcite-value-list-item value="f" text-label="F"></calcite-value-list-item>
</calcite-value-list>
`
});

await dragAndDrop(
page,
{
host: `calcite-value-list-item[value="d"]`,
shadow: `.${CSS.handle}`
},
`#first-letters`
);

await dragAndDrop(
page,
{
host: `calcite-value-list-item[value="e"]`,
shadow: `.${CSS.handle}`
},
`#numbers`
);

await dragAndDrop(
page,
{
host: `calcite-value-list-item[value="e"]`,
shadow: `.${CSS.handle}`
},
`#no-group`
);

const [first, second, third, fourth, fifth, sixth, seventh, eight, ninth] = await page.findAll(
"calcite-value-list-item"
);
expect(await first.getProperty("value")).toBe("a");
expect(await second.getProperty("value")).toBe("b");
expect(await third.getProperty("value")).toBe("d");
expect(await fourth.getProperty("value")).toBe("1");
expect(await fifth.getProperty("value")).toBe("2");
expect(await sixth.getProperty("value")).toBe("no-group");
expect(await seventh.getProperty("value")).toBe("c");
expect(await eight.getProperty("value")).toBe("e");
expect(await ninth.getProperty("value")).toBe("f");
});
});
});
8 changes: 7 additions & 1 deletion src/components/calcite-value-list/calcite-value-list.tsx
Expand Up @@ -64,6 +64,11 @@ export class CalciteValueList<
*/
@Prop({ reflect: true }) filterEnabled = false;

/**
* If this is set and drag is enabled, items can be dropped between lists of the same group.
*/
@Prop() group: string;

/**
* When true, content is waiting to be loaded. This state shows a busy indicator.
*/
Expand Down Expand Up @@ -182,7 +187,8 @@ export class CalciteValueList<
this.sortable = Sortable.create(this.el, {
handle: `.${CSS.handle}`,
draggable: "calcite-value-list-item",
onUpdate: () => {
group: this.group,
onSort: () => {
this.items = Array.from(this.el.querySelectorAll<ItemElement>("calcite-value-list-item"));
const values = this.items.map((item) => item.value);
this.calciteListOrderChange.emit(values);
Expand Down
2 changes: 1 addition & 1 deletion src/demos/value-list/advanced.html
Expand Up @@ -239,7 +239,7 @@ <h3>drag-enabled</h3>
valueList4.addEventListener("calciteListChange", (event) => {
console.log(event.detail);
});
valueList4.addEventListener("calciteValueListOrderChange", (event) => {
valueList4.addEventListener("calciteListOrderChange", (event) => {
console.log("sort order changed");
console.log(event.detail);
});
Expand Down
47 changes: 25 additions & 22 deletions src/demos/value-list/basic.html
Expand Up @@ -32,12 +32,6 @@ <h3>multiple</h3>
</calcite-action>
</calcite-value-list-item>
</calcite-value-list>
<script>
const valueList = document.querySelector("#one");
valueList.addEventListener("calciteListChange", (event) => {
console.log(event.detail);
});
</script>

<h2>ValueList - Multi-select w/ Filter</h2>
<h3>Pick many</h3>
Expand All @@ -55,12 +49,6 @@ <h3>Pick many</h3>
</calcite-action>
</calcite-value-list-item>
</calcite-value-list>
<script>
const valueList2 = document.querySelector("#two");
valueList2.addEventListener("calciteListChange", (event) => {
console.log(event.detail);
});
</script>

<h2>ValueList - drag and drop enabled</h2>
<h3>Re-order by dragging the handle</h3>
Expand All @@ -73,17 +61,32 @@ <h3>Re-order by dragging the handle</h3>
<calcite-value-list-item text-label="Entertainment" text-description="Toys and leisure" value="entertainment">
</calcite-value-list-item>
</calcite-value-list>
<script>
const valueList4 = document.querySelector("#four");
valueList4.addEventListener("calciteListChange", (event) => {
console.log(event.detail);
});
valueList4.addEventListener("calciteValueListOrderChange", (event) => {
console.log("sort order changed");
console.log(event.detail);
});
</script>

<h3>Drag and drop between different lists</h3>
<h4>List 1</h4>
<calcite-value-list id="five" drag-enabled group="draggable">
<calcite-value-list-item text-label="One" value="1"></calcite-value-list-item>
<calcite-value-list-item text-label="Two" value="2"></calcite-value-list-item>
</calcite-value-list>

<h4>List 2</h4>
<calcite-value-list id="six" drag-enabled group="draggable">
<calcite-value-list-item text-label="Three" value="3"></calcite-value-list-item>
<calcite-value-list-item text-label="Four" value="4"></calcite-value-list-item>
</calcite-value-list>
</section>

<script>
function setUpValueListEventListeners(valueList) {
valueList.addEventListener("calciteListChange", (event) => console.log(event.detail));

if (valueList.hasAttribute("drag-enabled")) {
valueList.addEventListener("calciteListOrderChange", (event) => console.log("sort order changed", event.detail));
}
}

Array.from(document.getElementsByTagName("calcite-value-list")).forEach(valueList => setUpValueListEventListeners(valueList));
</script>
</main>
</body>
</html>

0 comments on commit 1c35a0d

Please sign in to comment.