Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(list): include groups in filtering #10664

Merged
merged 33 commits into from
Jan 2, 2025

Conversation

anveshmekala
Copy link
Contributor

@anveshmekala anveshmekala commented Oct 31, 2024

Related Issue: #7702

Summary

  • Include calcite-list-item-group in filtering.
  • group's heading can be used as filterProp.

@github-actions github-actions bot added the bug Bug reports for broken functionality. Issues should include a reproduction of the bug. label Oct 31, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. Please close your PR if it is no longer relevant. Thank you for your contributions.

@github-actions github-actions bot added the Stale Issues or pull requests that have not had recent activity. label Nov 14, 2024
@anveshmekala anveshmekala removed the Stale Issues or pull requests that have not had recent activity. label Nov 14, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. Please close your PR if it is no longer relevant. Thank you for your contributions.

@github-actions github-actions bot added the Stale Issues or pull requests that have not had recent activity. label Nov 28, 2024
@anveshmekala anveshmekala removed the Stale Issues or pull requests that have not had recent activity. label Dec 2, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. Please close your PR if it is no longer relevant. Thank you for your contributions.

@github-actions github-actions bot added the Stale Issues or pull requests that have not had recent activity. label Dec 10, 2024
@github-actions github-actions bot removed the Stale Issues or pull requests that have not had recent activity. label Dec 13, 2024
@anveshmekala anveshmekala marked this pull request as ready for review December 20, 2024 21:27
@anveshmekala anveshmekala added the pr ready for visual snapshots Adding this label will run visual snapshot testing. label Dec 20, 2024
Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good @anveshmekala but have some feedback on implementation.

* @readonly
* @deprecated Use `filteredResults` instead.
*/
@property() filteredItems: ListElement[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anveshmekala can we leave filteredItems? Do we need to have a property that includes groups?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it is a short notice, its better to deprecate first. To avoid confusing with naming, filteredResults is added.

If we are including groups in filter, the user should be able to access the groups me thinks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of my reasoning for not including groups is that they aren't results. They can't be selected, they don't have a value, etc.

Copy link
Contributor Author

@anveshmekala anveshmekala Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree item-group is more of a presentational component, but using heading as filterProp can affect how filtering is done. And users should be able to lookup the API for any potential matches for filterText.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will make it easier if we don't include item-group in filteredItems but filteredItems can't be empty if there is a match.

Did think of adding direct children items of the item-group as filteredItems instead of the item-group but that can be misleading and not consistent with how items are added to filteredItems when item is nested inside a item without a group. Thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reviewing the issue again, I think the request was primarily visual and not related to filteredItems. My earlier context was minimal, so apologies for any confusion. 😅

I agree on including them when they are valueless is a bit odd.

Could we proceed with the behavior while keeping filteredItems as is?

@@ -160,7 +171,7 @@ export class List

@state() assistiveText: string;

@state() dataForFilter: ItemData = [];
@state() dataForFilter: (ItemData | ItemGroupData)[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of including separate group data, can we just add the group data to each item within a group? It would just be the heading property added to each item.

If we just added group heading to the itemData, then we wouldn't need the logic in filterGroupItems

Theres already existing logic to show a group if one or more items match and hide a group if not. The only part missing is the group data attached to each item.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above wouldn't work where only group heading is matched (nested group) but none of the items or ancestor group have a matching text.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anveshmekala it should work.

The current filtering only applies to items, but should also include groups and any matches should show all items under a matching group.

any matches should show all items under a matching group

According to the request, if a group matches, all items under that group should also match.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its working as expected! 🎉

{filteredItems.map((item) => (
<li>{item.label}</li>
{filteredResults.map((item) => (
<li role={(item as ListItemGroup).heading ? "group" : "none"}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For proper semantic structure, groups should be rendered as <ul> or <ol> and no roles would need to be set here. Setting the role to none is taking away from the list role which is automatically applied to <li> elements.

The structure should be like:

<ol>
<li>Group 1
  <ol>
    <li>item within group</li> 
    <li>item within group</li> 
 </ol>
</li>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, the role attribute wouldn't make a diff how AT handles the information. Idea was to provide the context about a possible group heading matched & semantic structure is not the right fit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point was that if you set the role to none on a list-item it takes away the default list-item role.

@@ -744,7 +761,7 @@ export class List
const filteredItems = filterPredicate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is currently structured, filterPredicate would only affect items and not groups.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meaning to ask, should the filterPredicate include groups? It wasn't mentioned here #3454 but (#7702) was created later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should, just wanted to point out the inconsistency with treating groups like items.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not, is the alternative metadata + filterProps? While functional, it introduces boilerplate for a common filtering workflow using information already present in the list.

Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting closer @anveshmekala! 👍

return this.listItems.map((item) => ({
label: item.label,
description: item.description,
metadata: item.metadata,
heading: item.parentElement?.closest(listItemGroupSelector)?.heading || "",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we store the parentGroup elements on connectedCallback? That way its only ever queried in the DOM one time. In this scenario its queried every time getItemData() is called.

The other part is that this is only getting the first parent group element. Shouldn't it get all ancestor group elements and map to their headings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other part is that this is only getting the first parent group element. Shouldn't it get all ancestor group elements and map to their headings?

Good catch. Each item should store the heading of all ancestors group elements.

let heading = "";
this.listItemGroups.forEach((group) => {
if (group.contains(item)) {
heading += group.heading;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also store heading of ancestor as Array object.

Leaning towards string concatenation for performance gains with filter method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was thinking array because string concat would match two words from different headings combined. Can we change to use an array here?

let heading = "";
this.listItemGroups.forEach((group) => {
if (group.contains(item)) {
heading += group.heading;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was thinking array because string concat would match two words from different headings combined. Can we change to use an array here?

@@ -649,6 +653,10 @@ export class List
}
}

private setListItemGroups(): void {
this.listItemGroups = Array.from(this.el.querySelectorAll(listItemGroupSelector));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other alternative would be something like this:

let ancestor = el.closest("calcite-list-item-group");
const headings: string[] = [];
while (ancestor) {
  headings.push(ancestor.heading);
  ancestor = ancestor.closest("calcite-list-item-group");
}

I'm not sure which would be more performant, calling closest() a few times on connectedCallback or calling setListItemGroups on each mutation. Thoughts @jcfranco?

@anveshmekala anveshmekala added pr ready for visual snapshots Adding this label will run visual snapshot testing. and removed pr ready for visual snapshots Adding this label will run visual snapshot testing. labels Dec 31, 2024
Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me 👍

The querying of groups comment is pretty minor and would require storing that information on each item so what you currently have seems to make the most sense.

@anveshmekala anveshmekala added pr ready for visual snapshots Adding this label will run visual snapshot testing. and removed pr ready for visual snapshots Adding this label will run visual snapshot testing. labels Jan 2, 2025
@anveshmekala anveshmekala requested a review from ashetland January 2, 2025 17:16
@anveshmekala anveshmekala merged commit 904623b into dev Jan 2, 2025
16 checks passed
@anveshmekala anveshmekala deleted the anveshmekala/7702-fix-list-filtering-groups branch January 2, 2025 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug reports for broken functionality. Issues should include a reproduction of the bug. pr ready for visual snapshots Adding this label will run visual snapshot testing.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants