Skip to content

Commit

Permalink
fix(list): changing filterText property will now update filtered items (
Browse files Browse the repository at this point in the history
#7133)

**Related Issue:** #6633

## Summary

- Depends on #7127
- Tidy's up tests and remove skipping.
- Watches `filterText` property and calls `filter` method when it
changes.
- Calls `filter` method once the filterEl has been rendered.
- Cleanup
  • Loading branch information
driskull authored Jun 28, 2023
1 parent 5a4283f commit a9c0bce
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 84 deletions.
123 changes: 60 additions & 63 deletions packages/calcite-components/src/components/list/list.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,28 @@ describe("calcite-list", () => {
);
});

it.skip("navigating items after filtering", async () => {
const page = await newE2EPage({
html: html`
<calcite-list filter-enabled>
<calcite-list-item value="one" label="One" description="hello world"></calcite-list-item>
<calcite-list-item value="two" label="Two" description="hello world"></calcite-list-item>
</calcite-list>
`
});
it("navigating items after filtering", async () => {
const page = await newE2EPage();
await page.setContent(html`
<calcite-list filter-enabled>
<calcite-list-item value="one" label="One" description="hello world"></calcite-list-item>
<calcite-list-item value="two" label="Two" description="hello world"></calcite-list-item>
</calcite-list>
`);
await page.waitForChanges();
const list = await page.find("calcite-list");
const filter = await page.find(`calcite-list >>> calcite-filter`);
await page.waitForTimeout(listDebounceTimeout);
expect(await list.getProperty("filteredItems")).toHaveLength(2);
expect(await list.getProperty("filteredData")).toHaveLength(2);
expect(await list.getProperty("filterText")).toBeUndefined();

await filter.callMethod("setFocus");

const calciteListFilterEvent = page.waitForEvent("calciteListFilter");
const calciteListFilterEvent = list.waitForEvent("calciteListFilter");
await page.keyboard.type("one");
await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
await calciteListFilterEvent;
expect(await list.getProperty("filteredItems")).toHaveLength(1);
expect(await list.getProperty("filteredData")).toHaveLength(1);
Expand All @@ -137,80 +137,77 @@ describe("calcite-list", () => {
await page.keyboard.press("Backspace");
await page.waitForChanges();

const calciteListFilterEvent2 = page.waitForEvent("calciteListFilter");
const calciteListFilterEvent2 = list.waitForEvent("calciteListFilter");
await page.keyboard.type("two");
await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
await calciteListFilterEvent2;
expect(await list.getProperty("filteredItems")).toHaveLength(1);
expect(await list.getProperty("filteredData")).toHaveLength(1);
expect(await list.getProperty("filterText")).toBe("two");

const calciteListFilterEvent3 = page.waitForEvent("calciteListFilter");
const calciteListFilterEvent3 = list.waitForEvent("calciteListFilter");
await page.keyboard.type("blah");
await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
await calciteListFilterEvent3;
expect(await list.getProperty("filteredItems")).toHaveLength(0);
expect(await list.getProperty("filteredData")).toHaveLength(0);
expect(await list.getProperty("filterText")).toBe("twoblah");
});

it.skip("filters initially", async () => {
const page = await newE2EPage({
html: html`
<calcite-list filter-enabled filter-text="match">
<calcite-list-item
id="label-match"
label="match"
description="description-1"
value="value-1"
></calcite-list-item>
<calcite-list-item
id="description-match"
label="label-2"
description="match"
value="value-1"
></calcite-list-item>
<calcite-list-item
id="value-match"
label="label-3"
description="description-3"
value="match"
></calcite-list-item>
<calcite-list-item
id="no-match"
label="label-4"
description="description-4"
value="value-4"
></calcite-list-item>
</calcite-list>
`
});
it("filters initially", async () => {
const page = await newE2EPage();
await page.setContent(html`
<calcite-list filter-enabled filter-text="match">
<calcite-list-item
id="label-match"
label="match"
description="description-1"
value="value-1"
></calcite-list-item>
<calcite-list-item
id="description-match"
label="label-2"
description="match"
value="value-1"
></calcite-list-item>
<calcite-list-item
id="value-match"
label="label-3"
description="description-3"
value="match"
></calcite-list-item>
<calcite-list-item
id="no-match"
label="label-4"
description="description-4"
value="value-4"
></calcite-list-item>
</calcite-list>
`);

await page.waitForChanges();
const list = await page.find("calcite-list");
await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();

expect(await list.getProperty("filteredData")).toHaveLength(3);
expect(await list.getProperty("filteredItems")).toHaveLength(3);
expect(await list.getProperty("filteredData")).toHaveLength(3);

const visibleItems = await page.findAll("calcite-list-item:not([hidden])");

expect(visibleItems.map((item) => item.id)).toEqual(["label-match", "description-match", "value-match"]);
});

it("should update active item on init and click", async () => {
const page = await newE2EPage({
html: html`<calcite-list selection-mode="none">
<calcite-list-item id="item-1" label="hello" description="world"></calcite-list-item>
<calcite-list-item id="item-2" label="hello 2" description="world 2"></calcite-list-item>
<calcite-list-item id="item-3" label="hello 3" description="world 3"></calcite-list-item>
</calcite-list>`
});

await page.waitForTimeout(listDebounceTimeout);
const page = await newE2EPage();
await page.setContent(html`<calcite-list selection-mode="none">
<calcite-list-item id="item-1" label="hello" description="world"></calcite-list-item>
<calcite-list-item id="item-2" label="hello 2" description="world 2"></calcite-list-item>
<calcite-list-item id="item-3" label="hello 3" description="world 3"></calcite-list-item>
</calcite-list>`);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);

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

Expand All @@ -222,8 +219,8 @@ describe("calcite-list", () => {

await items[1].click();

await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
expect(eventSpy).toHaveReceivedEventTimes(1);

expect(await items[0].getProperty("active")).toBe(false);
Expand All @@ -240,8 +237,8 @@ describe("calcite-list", () => {
</calcite-list>`
});

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

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

Expand All @@ -253,8 +250,8 @@ describe("calcite-list", () => {

await items[2].click();

await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
expect(eventSpy).toHaveReceivedEventTimes(1);

expect(await items[0].getProperty("selected")).toBe(false);
Expand All @@ -271,8 +268,8 @@ describe("calcite-list", () => {
</calcite-list>`
});

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

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

Expand All @@ -284,8 +281,8 @@ describe("calcite-list", () => {

await items[2].click();

await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
expect(eventSpy).toHaveReceivedEventTimes(1);

expect(await items[0].getProperty("selected")).toBe(false);
Expand All @@ -294,8 +291,8 @@ describe("calcite-list", () => {

await items[0].click();

await page.waitForTimeout(listDebounceTimeout);
await page.waitForChanges();
await page.waitForTimeout(listDebounceTimeout);
expect(eventSpy).toHaveReceivedEventTimes(2);

expect(await items[0].getProperty("selected")).toBe(true);
Expand Down
69 changes: 48 additions & 21 deletions packages/calcite-components/src/components/list/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ export class List implements InteractiveComponent, LoadableComponent {
*/
@Prop({ reflect: true, mutable: true }) filterText: string;

@Watch("filterText")
async handleFilterTextChange(): Promise<void> {
this.performFilter();
}

/**
* Specifies an accessible name for the component.
*/
Expand Down Expand Up @@ -224,14 +229,6 @@ export class List implements InteractiveComponent, LoadableComponent {

componentDidLoad(): void {
setComponentLoaded(this);
const { filterEl } = this;
const filteredItems = filterEl?.filteredItems as ItemData;

if (filteredItems) {
this.filteredData = filteredItems;
}

this.updateListItems();
}

// --------------------------------------------------------------------------
Expand Down Expand Up @@ -299,11 +296,11 @@ export class List implements InteractiveComponent, LoadableComponent {
aria-label={filterPlaceholder}
disabled={loading || disabled}
items={dataForFilter}
onCalciteFilterChange={this.handleFilter}
onCalciteFilterChange={this.handleFilterChange}
placeholder={filterPlaceholder}
value={filterText}
// eslint-disable-next-line react/jsx-sort-props
ref={(el) => (this.filterEl = el)}
ref={this.setFilterEl}
/>
</th>
</tr>
Expand All @@ -323,11 +320,11 @@ export class List implements InteractiveComponent, LoadableComponent {
//
// --------------------------------------------------------------------------

handleDefaultSlotChange = (event: Event): void => {
private handleDefaultSlotChange = (event: Event): void => {
updateListItemChildren(getListItemChildren(event));
};

setActiveListItem = (): void => {
private setActiveListItem = (): void => {
const { enabledListItems } = this;

if (!enabledListItems.some((item) => item.active)) {
Expand Down Expand Up @@ -402,15 +399,45 @@ export class List implements InteractiveComponent, LoadableComponent {
}
};

handleFilter = (event: CustomEvent): void => {
private updateFilteredData(emit = false): void {
const { filterEl } = this;

if (!filterEl) {
return;
}

if (filterEl.filteredItems) {
this.filteredData = filterEl.filteredItems as ItemData;
}

this.updateListItems(emit);
}

private async performFilter(): Promise<void> {
const { filterEl, filterText } = this;

if (!filterEl) {
return;
}

filterEl.value = filterText;
await filterEl.filter(filterText);
this.updateFilteredData();
}

private setFilterEl = (el: HTMLCalciteFilterElement): void => {
this.filterEl = el;
this.performFilter();
};

private handleFilterChange = (event: CustomEvent): void => {
event.stopPropagation();
const { filteredItems, value } = event.currentTarget as HTMLCalciteFilterElement;
this.filteredData = filteredItems as ItemData;
const { value } = event.currentTarget as HTMLCalciteFilterElement;
this.filterText = value;
this.updateListItems(true);
this.updateFilteredData(true);
};

getItemData = (): ItemData => {
private getItemData = (): ItemData => {
return this.listItems.map((item) => ({
label: item.label,
description: item.description,
Expand Down Expand Up @@ -439,11 +466,11 @@ export class List implements InteractiveComponent, LoadableComponent {
this.updateSelectedItems(emit);
}, debounceTimeout);

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

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

if (!focusEl) {
Expand All @@ -455,7 +482,7 @@ export class List implements InteractiveComponent, LoadableComponent {
focusEl.setFocus();
};

isNavigable = (listItem: HTMLCalciteListItemElement): boolean => {
private isNavigable = (listItem: HTMLCalciteListItemElement): boolean => {
const parentListItemEl = listItem.parentElement?.closest(listItemSelector);

if (!parentListItemEl) {
Expand All @@ -465,7 +492,7 @@ export class List implements InteractiveComponent, LoadableComponent {
return parentListItemEl.open && this.isNavigable(parentListItemEl);
};

handleListKeydown = (event: KeyboardEvent): void => {
private handleListKeydown = (event: KeyboardEvent): void => {
if (event.defaultPrevented) {
return;
}
Expand Down

0 comments on commit a9c0bce

Please sign in to comment.