Skip to content
Permalink
Browse files
feat: Render non-searchable items in AutoComplete
Since it can sometimes be helpful to render additional items that are
not searchable and mostly for presentation, the AutoComplete was updated
to have `beforeResultsChildren` and `afterResultsChildren` props. The
`afterResultsChildren` prop is good to use for fetching additional
results for paginated auto completion.
  • Loading branch information
mlaursen committed Jul 12, 2020
1 parent 56cda1f commit e7a82acf874f46b56e8427cdb389ff1f18f12927
Showing 4 changed files with 275 additions and 0 deletions.
@@ -80,6 +80,8 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
omitKeys = EMPTY_LIST,
value: propValue,
defaultValue,
beforeResultsChildren,
afterResultsChildren,
...props
},
forwardedRef
@@ -185,6 +187,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
style={fixedStyle}
className={cn(listbox({ temporary: true }), listboxClassName)}
>
{beforeResultsChildren}
{filteredData.map((datum, i) => {
const resultId = getResultId(suggestionsId, i);
let optionProps: ListboxOptionProps | undefined;
@@ -215,6 +218,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
</Option>
);
})}
{afterResultsChildren}
</List>
</ScaleTransition>
</>
@@ -307,6 +311,8 @@ if (process.env.NODE_ENV !== "production") {
omitKeys: PropTypes.arrayOf(PropTypes.string),
value: PropTypes.string,
defaultValue: PropTypes.string,
beforeResultsChildren: PropTypes.node,
afterResultsChildren: PropTypes.node,
};
} catch (e) {}
}
@@ -195,4 +195,46 @@ describe("AutoComplete", () => {
expect(getListbox).toThrow();
fireEvent.blur(input);
});

it("should be able to render content before and after the matching data", () => {
const beforeResultsChildren = <div>Before Results</div>;
const afterResultsChildren = <div>After Results</div>;
const { getByText, getByRole } = render(
<AutoComplete
{...PROPS}
data={states.slice(0, 5)}
beforeResultsChildren={beforeResultsChildren}
afterResultsChildren={afterResultsChildren}
/>
);

const input = getById<HTMLInputElement>("autocomplete");
const getListbox = () => getByRole("listbox");
const getBeforeResults = () => getByText("Before Results");
const getAfterResults = () => getByText("After Results");

expect(getBeforeResults).toThrow();
expect(getAfterResults).toThrow();

fireEvent.focus(input);
expect(getBeforeResults).not.toThrow();
expect(getAfterResults).not.toThrow();

const listbox = getListbox();
expect(listbox.firstChild?.textContent).toBe("Before Results");
expect(listbox.lastChild?.textContent).toBe("After Results");
expect(listbox).toMatchSnapshot();

// filtered matches
fireEvent.change(input, { value: "Am" });
expect(listbox.firstChild?.textContent).toBe("Before Results");
expect(listbox.lastChild?.textContent).toBe("After Results");
expect(listbox).toMatchSnapshot();

// no matches
fireEvent.change(input, { value: "Aml" });
expect(listbox.firstChild?.textContent).toBe("Before Results");
expect(listbox.lastChild?.textContent).toBe("After Results");
expect(listbox).toMatchSnapshot();
});
});
@@ -1,5 +1,218 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AutoComplete should be able to render content before and after the matching data 1`] = `
<ul
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
>
<div>
Before Results
</div>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-1"
role="option"
>
<span
class="rmd-list-item__text"
>
Alabama
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-2"
role="option"
>
<span
class="rmd-list-item__text"
>
Alaska
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-3"
role="option"
>
<span
class="rmd-list-item__text"
>
American Samoa
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-4"
role="option"
>
<span
class="rmd-list-item__text"
>
Arizona
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-5"
role="option"
>
<span
class="rmd-list-item__text"
>
Arkansas
</span>
</li>
<div>
After Results
</div>
</ul>
`;

exports[`AutoComplete should be able to render content before and after the matching data 2`] = `
<ul
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
>
<div>
Before Results
</div>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-1"
role="option"
>
<span
class="rmd-list-item__text"
>
Alabama
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-2"
role="option"
>
<span
class="rmd-list-item__text"
>
Alaska
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-3"
role="option"
>
<span
class="rmd-list-item__text"
>
American Samoa
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-4"
role="option"
>
<span
class="rmd-list-item__text"
>
Arizona
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-5"
role="option"
>
<span
class="rmd-list-item__text"
>
Arkansas
</span>
</li>
<div>
After Results
</div>
</ul>
`;

exports[`AutoComplete should be able to render content before and after the matching data 3`] = `
<ul
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
id="autocomplete-listbox"
role="listbox"
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
>
<div>
Before Results
</div>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-1"
role="option"
>
<span
class="rmd-list-item__text"
>
Alabama
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-2"
role="option"
>
<span
class="rmd-list-item__text"
>
Alaska
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-3"
role="option"
>
<span
class="rmd-list-item__text"
>
American Samoa
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-4"
role="option"
>
<span
class="rmd-list-item__text"
>
Arizona
</span>
</li>
<li
class="rmd-list-item rmd-list-item--clickable rmd-option"
id="autocomplete-listbox-result-5"
role="option"
>
<span
class="rmd-list-item__text"
>
Arkansas
</span>
</li>
<div>
After Results
</div>
</ul>
`;

exports[`AutoComplete should handle a normal filter flow 1`] = `
<div>
<div
@@ -289,4 +289,18 @@ export interface AutoCompleteProps
*```
*/
omitKeys?: readonly string[];

/**
* Any optional children to display before the matched results in the
* autocomplete's menu. This should normally be for any presentational data or
* things that should not be searchable.
*/
beforeResultsChildren?: ReactNode;

/**
* Any optional children to display after the matched results in the
* autocomplete's menu. This should normally be for any presentational data or
* things that should not be searchable.
*/
afterResultsChildren?: ReactNode;
}

0 comments on commit e7a82ac

Please sign in to comment.