Skip to content

Commit

Permalink
fix(list): enable dragging on list items contained within a list that…
Browse files Browse the repository at this point in the history
… supports dragEnabled (#9660)

**Related Issue:** #9662

## Summary

I'd like to get this one in to support work in Maps SDK.

A limitation of the Maquette VDOM is that it creates a "div" for every
new widget. So in order to make a list item as a widget it needs to
support `calcite-list-item`s wrapped in divs.

- Support dragging on list-items that are not direct children of a list
- Add tests
  • Loading branch information
driskull committed Jun 21, 2024
1 parent 381bcca commit 5010ef9
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 12 deletions.
106 changes: 106 additions & 0 deletions packages/calcite-components/src/components/list/list.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,112 @@ describe("calcite-list", () => {
{ focusTarget: "child" },
);

it("should set the dragHandle property on items", async () => {
const page = await newE2EPage();
await page.setContent(
html`<calcite-list id="root" drag-enabled group="my-list">
<calcite-list-item open label="Depth 1" description="Item 1">
<calcite-list group="my-list">
<calcite-list-item open label="Depth 2" description="Item 2">
<calcite-list drag-enabled group="my-list">
<calcite-list-item label="Depth 3" description="Item 3">
<calcite-list drag-enabled group="my-list"></calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 3" description="Item 4"></calcite-list-item>
</calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 2" description="Item 5"></calcite-list-item>
</calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 1" description="Item 6"></calcite-list-item>
<calcite-list-item drag-disabled label="Depth 1" description="Item 7"></calcite-list-item>
</calcite-list>`,
);

await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);

let dragHandleValues = [true, false, true, true, false, true, true];

const items = await page.findAll("calcite-list-item");

expect(items.length).toBe(dragHandleValues.length);

for (let i = 0; i < items.length; i++) {
expect(await items[i].getProperty("dragHandle")).toBe(dragHandleValues[i]);
}

const rootList = await page.find("#root");

rootList.setProperty("dragEnabled", false);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);

dragHandleValues = [false, false, true, true, false, false, false];

expect(items.length).toBe(dragHandleValues.length);

for (let i = 0; i < items.length; i++) {
expect(await items[i].getProperty("dragHandle")).toBe(dragHandleValues[i]);
}
});

it("should set the dragHandle property on items which are not direct children", async () => {
const page = await newE2EPage();
await page.setContent(
html`<calcite-list id="root" drag-enabled group="my-list">
<div>
<calcite-list-item open label="Depth 1" description="Item 1">
<calcite-list group="my-list">
<div>
<calcite-list-item open label="Depth 2" description="Item 2">
<calcite-list drag-enabled group="my-list">
<div>
<calcite-list-item label="Depth 3" description="Item 3">
<calcite-list drag-enabled group="my-list"></calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 3" description="Item 4"></calcite-list-item></div>
</calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 2" description="Item 5"></calcite-list-item></div>
</calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 1" description="Item 6"></calcite-list-item></div>
<div><calcite-list-item drag-disabled label="Depth 1" description="Item 7"></calcite-list-item></div>
</calcite-list>`,
);

await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);

let dragHandleValues = [true, false, true, true, false, true, true];

const items = await page.findAll("calcite-list-item");

expect(items.length).toBe(dragHandleValues.length);

for (let i = 0; i < items.length; i++) {
expect(await items[i].getProperty("dragHandle")).toBe(dragHandleValues[i]);
}

const rootList = await page.find("#root");

rootList.setProperty("dragEnabled", false);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);

dragHandleValues = [false, false, true, true, false, false, false];

expect(items.length).toBe(dragHandleValues.length);

for (let i = 0; i < items.length; i++) {
expect(await items[i].getProperty("dragHandle")).toBe(dragHandleValues[i]);
}
});

it("disabling and enabling an item restores actions from being tabbable", async () => {
const page = await newE2EPage();
await page.setContent(html`
Expand Down
44 changes: 44 additions & 0 deletions packages/calcite-components/src/components/list/list.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1077,3 +1077,47 @@ export const closedItems_TestOnly = (): string =>
>
</calcite-list-item>
</calcite-list>`;

export const dragEnabledNestedLists = (): string =>
html`<calcite-list id="root" drag-enabled group="my-list">
<calcite-list-item open label="Depth 1" description="Item 1">
<calcite-list group="my-list">
<calcite-list-item open label="Depth 2" description="Item 2">
<calcite-list drag-enabled group="my-list">
<calcite-list-item label="Depth 3" description="Item 3">
<calcite-list drag-enabled group="my-list"></calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 3" description="Item 4"></calcite-list-item>
</calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 2" description="Item 5"></calcite-list-item>
</calcite-list>
</calcite-list-item>
<calcite-list-item label="Depth 1" description="Item 6"></calcite-list-item>
<calcite-list-item drag-disabled label="Depth 1" description="Item 7"></calcite-list-item>
</calcite-list>`;

export const dragEnabledNestedListsIndirectChildren = (): string =>
html`<calcite-list id="root" drag-enabled group="my-list">
<div>
<calcite-list-item open label="Depth 1" description="Item 1">
<calcite-list group="my-list">
<div>
<calcite-list-item open label="Depth 2" description="Item 2">
<calcite-list drag-enabled group="my-list">
<div>
<calcite-list-item label="Depth 3" description="Item 3">
<calcite-list drag-enabled group="my-list"></calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 3" description="Item 4"></calcite-list-item></div>
</calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 2" description="Item 5"></calcite-list-item></div>
</calcite-list>
</calcite-list-item>
</div>
<div><calcite-list-item label="Depth 1" description="Item 6"></calcite-list-item></div>
<div><calcite-list-item drag-disabled label="Depth 1" description="Item 7"></calcite-list-item></div>
</calcite-list>`;
18 changes: 6 additions & 12 deletions packages/calcite-components/src/components/list/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import { ListMessages } from "./assets/list/t9n";
import { ListDragDetail } from "./interfaces";

const listItemSelector = "calcite-list-item";
const listItemSelectorDirect = `:scope > calcite-list-item`;
const parentSelector = "calcite-list-item-group, calcite-list-item";

/**
Expand Down Expand Up @@ -837,17 +836,16 @@ export class List
};

private updateListItems = debounce((emit = false): void => {
const { selectionAppearance, selectionMode, dragEnabled } = this;
const { selectionAppearance, selectionMode, dragEnabled, el } = this;

const items = Array.from(this.el.querySelectorAll(listItemSelector));

const items = this.queryListItems();
items.forEach((item) => {
item.selectionAppearance = selectionAppearance;
item.selectionMode = selectionMode;
});

const directItems = this.queryListItems(true);
directItems.forEach((item) => {
item.dragHandle = dragEnabled;
if (item.closest("calcite-list") === el) {
item.dragHandle = dragEnabled;
}
});

if (this.parentListEl) {
Expand All @@ -871,10 +869,6 @@ export class List
this.setUpSorting();
}, debounceTimeout);

private queryListItems = (direct = false): HTMLCalciteListItemElement[] => {
return Array.from(this.el.querySelectorAll(direct ? listItemSelectorDirect : listItemSelector));
};

private focusRow = (focusEl: HTMLCalciteListItemElement): void => {
const { focusableItems } = this;

Expand Down

0 comments on commit 5010ef9

Please sign in to comment.