Skip to content

Commit

Permalink
feat(picker): add default searcher function for simple client-side fi…
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianschmidt committed Dec 20, 2024
1 parent f8c6c06 commit 36e5f54
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 142 deletions.
4 changes: 3 additions & 1 deletion etc/lime-elements.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ export namespace Components {
"actionPosition": ActionPosition;
"actions": Array<ListItem<Action>>;
"actionScrollBehavior": ActionScrollBehavior;
"allItems"?: Array<ListItem<PickerValue>>;
"badgeIcons": boolean;
"delimiter": string;
"disabled": boolean;
Expand All @@ -565,7 +566,7 @@ export namespace Components {
"multiple": boolean;
"readonly": boolean;
"required": boolean;
"searcher": Searcher;
"searcher"?: Searcher;
"searchLabel": string;
"value": ListItem<PickerValue> | Array<ListItem<PickerValue>>;
}
Expand Down Expand Up @@ -1582,6 +1583,7 @@ namespace JSX_2 {
"actionPosition"?: ActionPosition;
"actions"?: Array<ListItem<Action>>;
"actionScrollBehavior"?: ActionScrollBehavior;
"allItems"?: Array<ListItem<PickerValue>>;
"badgeIcons"?: boolean;
"delimiter"?: string;
"disabled"?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ import { Component, h, State } from '@stencil/core';
/**
* Single value can be picked.
*
* - "Search" is done locally in the frontend.
* Since all items are already loaded from the server, we can use the
* `allItems` property to provide the picker with all the items at once.
* The picker uses a default search function that filters the items based on
* the `text` and `secondaryText` properties of the items.
*
* :::note
* For performance reasons, the default searcher will never return more
* than 20 items, but if there are more than 20 items, the rest can be
* found by typing more characters in the search field.
* :::
*/
@Component({
tag: 'limel-example-picker-single',
tag: 'limel-example-picker-basic',
shadow: true,
})
export class PickerSingleExample {
export class PickerBasicExample {
@State()
private selectedItem: ListItem<number>;

Expand All @@ -35,28 +44,15 @@ export class PickerSingleExample {
<limel-picker
label="Favorite awesomenaut"
value={this.selectedItem}
searcher={this.search}
allItems={this.allItems}
emptyResultMessage="No matching awesomenauts found"
onChange={this.onChange}
onInteract={this.onInteract}
/>,
<limel-example-value value={this.selectedItem} />,
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
return resolve(this.allItems);
}

const filteredItems = this.allItems.filter((item) => {
return item.text.toLowerCase().includes(query.toLowerCase());
});

return resolve(filteredItems);
});
};

private onChange = (event: LimelPickerCustomEvent<ListItem<number>>) => {
this.selectedItem = event.detail;
};
Expand Down
17 changes: 2 additions & 15 deletions src/components/picker/examples/picker-composite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class PickerCompositeExample {
delete schema.properties.actionPosition;
delete schema.properties.actionScrollBehavior;
delete schema.properties.actions;
delete schema.properties.allItems;
delete schema.properties.searcher;
this.schema = schema;
}
Expand All @@ -74,7 +75,7 @@ export class PickerCompositeExample {
return [
<limel-picker
{...this.props}
searcher={this.search}
allItems={this.availableItems}
onChange={this.handleChange}
onInteract={this.handleEvent}
/>,
Expand All @@ -85,20 +86,6 @@ export class PickerCompositeExample {
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
return resolve(this.availableItems);
}

const filteredItems = this.availableItems.filter((item) => {
return item.text.toLowerCase().includes(query.toLowerCase());
});

return resolve(filteredItems);
});
};

private handleChange = (
event: CustomEvent<
ListItem<number | string> | Array<ListItem<number | string>>
Expand Down
10 changes: 8 additions & 2 deletions src/components/picker/examples/picker-empty-suggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { Component, h, State } from '@stencil/core';
const NETWORK_DELAY = 500;

/**
* With no suggestions and a message for empty search results
* With a custom search function
*
* The custom search function returns two suggestions if the query is empty.
* Otherwise, it filters the items based on the query.
*
* :::important
* This example simulates that searching is done on the server. Because these
Expand Down Expand Up @@ -56,8 +59,11 @@ export class PickerExample {
if (query === '') {
// Simulate some network delay
setTimeout(() => {
resolve([]);
const result = this.allItems.slice(8, 10);
resolve(result);
}, NETWORK_DELAY);

return;
}

// Simulate some network delay
Expand Down
21 changes: 2 additions & 19 deletions src/components/picker/examples/picker-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,32 +144,15 @@ export class PickerIconsExample {
value={this.selectedItems}
searchLabel={'Search your awesomenaut'}
multiple={true}
searcher={this.search}
allItems={this.allItems}
emptyResultMessage="No matching awesomenauts found"
onChange={this.onChange}
onInteract={this.onInteract}
/>,
<limel-example-value value={this.selectedItems} />,
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
resolve([]);
}

const filteredItems = this.allItems.filter((item) => {
const searchText =
item.text.toLowerCase() +
' ' +
item.secondaryText.toLowerCase();

return searchText.includes(query.toLowerCase());
});
resolve(filteredItems);
});
};

private onChange = (
event: LimelPickerCustomEvent<Array<ListItem<number>>>,
) => {
Expand Down
16 changes: 2 additions & 14 deletions src/components/picker/examples/picker-leading-icon-example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export class PickerLeadingIconExample {
label="Favorite awesomenaut"
leadingIcon="search"
value={this.selectedItem}
searcher={this.search}
allItems={this.allItems}
emptyResultMessage="No results"
onChange={this.onChange}
onInteract={this.onInteract}
/>,
Expand All @@ -44,19 +45,6 @@ export class PickerLeadingIconExample {
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
resolve(this.allItems);
}

const filteredItems = this.allItems.filter((item) => {
return item.text.toLowerCase().includes(query.toLowerCase());
});
resolve(filteredItems);
});
};

private onChange = (event: LimelPickerCustomEvent<ListItem<number>>) => {
this.selectedItem = event.detail;
};
Expand Down
18 changes: 2 additions & 16 deletions src/components/picker/examples/picker-multiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Component, h, State } from '@stencil/core';
/**
* Multiple values can be picked.
*
* - "Search" is done locally in the frontend.
* - Already picked items are removed from the available options.
*/
@Component({
Expand Down Expand Up @@ -39,28 +38,15 @@ export class PickerMultipleExample {
label="Favorite awesomenaut"
value={this.selectedItems}
multiple={true}
searcher={this.search}
allItems={this.availableItems}
emptyResultMessage="No matching awesomenauts found"
onChange={this.onChange}
onInteract={this.onInteract}
/>,
<limel-example-value value={this.selectedItems} />,
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
return resolve(this.availableItems);
}

const filteredItems = this.availableItems.filter((item) => {
return item.text.toLowerCase().includes(query.toLowerCase());
});

return resolve(filteredItems);
});
};

private onChange = (
event: LimelPickerCustomEvent<Array<ListItem<number>>>,
) => {
Expand Down
16 changes: 1 addition & 15 deletions src/components/picker/examples/picker-static-action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export class PickerStaticActionsExample {
private actionPosition: Option<ActionPosition> = this.actionPositions[0];

constructor() {
this.search = this.search.bind(this);
this.onChange = this.onChange.bind(this);
this.onAction = this.onAction.bind(this);
this.setBehavior = this.setBehavior.bind(this);
Expand All @@ -99,7 +98,7 @@ export class PickerStaticActionsExample {
label="Select your favorite pet"
value={this.selectedItem}
searchLabel={'Search your awesomenaut'}
searcher={this.search}
allItems={this.allItems}
onChange={this.onChange}
onInteract={this.onInteract}
onAction={this.onAction}
Expand Down Expand Up @@ -133,19 +132,6 @@ export class PickerStaticActionsExample {
];
}

private search(query: string): Promise<ListItem[]> {
return new Promise((resolve) => {
if (query === '') {
resolve(this.allItems);
}

const filteredItems = this.allItems.filter((item) => {
return item.text.toLowerCase().includes(query.toLowerCase());
});
resolve(filteredItems);
});
}

private onChange(event: LimelPickerCustomEvent<ListItem<number>>) {
this.selectedItem = event.detail;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ export class PickerValueAsObjectWithActionsExample {
label="Favorite authors"
value={this.selectedItems}
searchLabel={'Find your favorite authors'}
emptyResultMessage="No matching authors found"
multiple={true}
searcher={this.search}
allItems={this.allItems}
onChange={this.onChange}
onInteract={this.onInteract}
/>
Expand All @@ -81,24 +82,6 @@ export class PickerValueAsObjectWithActionsExample {
);
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
resolve([]);
}

const filteredItems = this.allItems.filter((item) => {
const searchText =
item.text.toLowerCase() +
' ' +
item.secondaryText.toLowerCase();

return searchText.includes(query.toLowerCase());
});
resolve(filteredItems);
});
};

private onChange = (
event: LimelPickerCustomEvent<
Array<
Expand Down
23 changes: 3 additions & 20 deletions src/components/picker/examples/picker-value-as-object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,17 @@ export class PickerValueAsObjectExample {
<limel-picker
label="Favorite authors"
value={this.selectedItems}
searchLabel={'Search your favorite authors'}
searchLabel="Search your favorite authors"
emptyResultMessage="No matching authors found"
multiple={true}
searcher={this.search}
allItems={this.allItems}
onChange={this.onChange}
onInteract={this.onInteract}
/>,
<limel-example-value value={this.selectedItems} />,
];
}

private search = (query: string): Promise<ListItem[]> => {
return new Promise((resolve) => {
if (query === '') {
resolve([]);
}

const filteredItems = this.allItems.filter((item) => {
const searchText =
item.text.toLowerCase() +
' ' +
item.secondaryText.toLowerCase();

return searchText.includes(query.toLowerCase());
});
resolve(filteredItems);
});
};

private onChange = (
event: LimelPickerCustomEvent<
Array<
Expand Down
Loading

0 comments on commit 36e5f54

Please sign in to comment.