Skip to content

Commit e7a82ac

Browse files
committed
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.
1 parent 56cda1f commit e7a82ac

File tree

4 files changed

+275
-0
lines changed

4 files changed

+275
-0
lines changed

packages/autocomplete/src/AutoComplete.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
8080
omitKeys = EMPTY_LIST,
8181
value: propValue,
8282
defaultValue,
83+
beforeResultsChildren,
84+
afterResultsChildren,
8385
...props
8486
},
8587
forwardedRef
@@ -185,6 +187,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
185187
style={fixedStyle}
186188
className={cn(listbox({ temporary: true }), listboxClassName)}
187189
>
190+
{beforeResultsChildren}
188191
{filteredData.map((datum, i) => {
189192
const resultId = getResultId(suggestionsId, i);
190193
let optionProps: ListboxOptionProps | undefined;
@@ -215,6 +218,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoCompleteProps>(
215218
</Option>
216219
);
217220
})}
221+
{afterResultsChildren}
218222
</List>
219223
</ScaleTransition>
220224
</>
@@ -307,6 +311,8 @@ if (process.env.NODE_ENV !== "production") {
307311
omitKeys: PropTypes.arrayOf(PropTypes.string),
308312
value: PropTypes.string,
309313
defaultValue: PropTypes.string,
314+
beforeResultsChildren: PropTypes.node,
315+
afterResultsChildren: PropTypes.node,
310316
};
311317
} catch (e) {}
312318
}

packages/autocomplete/src/__tests__/AutoComplete.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,46 @@ describe("AutoComplete", () => {
195195
expect(getListbox).toThrow();
196196
fireEvent.blur(input);
197197
});
198+
199+
it("should be able to render content before and after the matching data", () => {
200+
const beforeResultsChildren = <div>Before Results</div>;
201+
const afterResultsChildren = <div>After Results</div>;
202+
const { getByText, getByRole } = render(
203+
<AutoComplete
204+
{...PROPS}
205+
data={states.slice(0, 5)}
206+
beforeResultsChildren={beforeResultsChildren}
207+
afterResultsChildren={afterResultsChildren}
208+
/>
209+
);
210+
211+
const input = getById<HTMLInputElement>("autocomplete");
212+
const getListbox = () => getByRole("listbox");
213+
const getBeforeResults = () => getByText("Before Results");
214+
const getAfterResults = () => getByText("After Results");
215+
216+
expect(getBeforeResults).toThrow();
217+
expect(getAfterResults).toThrow();
218+
219+
fireEvent.focus(input);
220+
expect(getBeforeResults).not.toThrow();
221+
expect(getAfterResults).not.toThrow();
222+
223+
const listbox = getListbox();
224+
expect(listbox.firstChild?.textContent).toBe("Before Results");
225+
expect(listbox.lastChild?.textContent).toBe("After Results");
226+
expect(listbox).toMatchSnapshot();
227+
228+
// filtered matches
229+
fireEvent.change(input, { value: "Am" });
230+
expect(listbox.firstChild?.textContent).toBe("Before Results");
231+
expect(listbox.lastChild?.textContent).toBe("After Results");
232+
expect(listbox).toMatchSnapshot();
233+
234+
// no matches
235+
fireEvent.change(input, { value: "Aml" });
236+
expect(listbox.firstChild?.textContent).toBe("Before Results");
237+
expect(listbox.lastChild?.textContent).toBe("After Results");
238+
expect(listbox).toMatchSnapshot();
239+
});
198240
});

packages/autocomplete/src/__tests__/__snapshots__/AutoComplete.tsx.snap

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,218 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`AutoComplete should be able to render content before and after the matching data 1`] = `
4+
<ul
5+
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
6+
id="autocomplete-listbox"
7+
role="listbox"
8+
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
9+
>
10+
<div>
11+
Before Results
12+
</div>
13+
<li
14+
class="rmd-list-item rmd-list-item--clickable rmd-option"
15+
id="autocomplete-listbox-result-1"
16+
role="option"
17+
>
18+
<span
19+
class="rmd-list-item__text"
20+
>
21+
Alabama
22+
</span>
23+
</li>
24+
<li
25+
class="rmd-list-item rmd-list-item--clickable rmd-option"
26+
id="autocomplete-listbox-result-2"
27+
role="option"
28+
>
29+
<span
30+
class="rmd-list-item__text"
31+
>
32+
Alaska
33+
</span>
34+
</li>
35+
<li
36+
class="rmd-list-item rmd-list-item--clickable rmd-option"
37+
id="autocomplete-listbox-result-3"
38+
role="option"
39+
>
40+
<span
41+
class="rmd-list-item__text"
42+
>
43+
American Samoa
44+
</span>
45+
</li>
46+
<li
47+
class="rmd-list-item rmd-list-item--clickable rmd-option"
48+
id="autocomplete-listbox-result-4"
49+
role="option"
50+
>
51+
<span
52+
class="rmd-list-item__text"
53+
>
54+
Arizona
55+
</span>
56+
</li>
57+
<li
58+
class="rmd-list-item rmd-list-item--clickable rmd-option"
59+
id="autocomplete-listbox-result-5"
60+
role="option"
61+
>
62+
<span
63+
class="rmd-list-item__text"
64+
>
65+
Arkansas
66+
</span>
67+
</li>
68+
<div>
69+
After Results
70+
</div>
71+
</ul>
72+
`;
73+
74+
exports[`AutoComplete should be able to render content before and after the matching data 2`] = `
75+
<ul
76+
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
77+
id="autocomplete-listbox"
78+
role="listbox"
79+
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
80+
>
81+
<div>
82+
Before Results
83+
</div>
84+
<li
85+
class="rmd-list-item rmd-list-item--clickable rmd-option"
86+
id="autocomplete-listbox-result-1"
87+
role="option"
88+
>
89+
<span
90+
class="rmd-list-item__text"
91+
>
92+
Alabama
93+
</span>
94+
</li>
95+
<li
96+
class="rmd-list-item rmd-list-item--clickable rmd-option"
97+
id="autocomplete-listbox-result-2"
98+
role="option"
99+
>
100+
<span
101+
class="rmd-list-item__text"
102+
>
103+
Alaska
104+
</span>
105+
</li>
106+
<li
107+
class="rmd-list-item rmd-list-item--clickable rmd-option"
108+
id="autocomplete-listbox-result-3"
109+
role="option"
110+
>
111+
<span
112+
class="rmd-list-item__text"
113+
>
114+
American Samoa
115+
</span>
116+
</li>
117+
<li
118+
class="rmd-list-item rmd-list-item--clickable rmd-option"
119+
id="autocomplete-listbox-result-4"
120+
role="option"
121+
>
122+
<span
123+
class="rmd-list-item__text"
124+
>
125+
Arizona
126+
</span>
127+
</li>
128+
<li
129+
class="rmd-list-item rmd-list-item--clickable rmd-option"
130+
id="autocomplete-listbox-result-5"
131+
role="option"
132+
>
133+
<span
134+
class="rmd-list-item__text"
135+
>
136+
Arkansas
137+
</span>
138+
</li>
139+
<div>
140+
After Results
141+
</div>
142+
</ul>
143+
`;
144+
145+
exports[`AutoComplete should be able to render content before and after the matching data 3`] = `
146+
<ul
147+
class="rmd-list rmd-listbox rmd-listbox--temporary rmd-transition--scale-y-enter rmd-transition--scale-y-enter-active"
148+
id="autocomplete-listbox"
149+
role="listbox"
150+
style="left: 0px; top: 0px; width: 0px; position: fixed; transform-origin: 50% 0;"
151+
>
152+
<div>
153+
Before Results
154+
</div>
155+
<li
156+
class="rmd-list-item rmd-list-item--clickable rmd-option"
157+
id="autocomplete-listbox-result-1"
158+
role="option"
159+
>
160+
<span
161+
class="rmd-list-item__text"
162+
>
163+
Alabama
164+
</span>
165+
</li>
166+
<li
167+
class="rmd-list-item rmd-list-item--clickable rmd-option"
168+
id="autocomplete-listbox-result-2"
169+
role="option"
170+
>
171+
<span
172+
class="rmd-list-item__text"
173+
>
174+
Alaska
175+
</span>
176+
</li>
177+
<li
178+
class="rmd-list-item rmd-list-item--clickable rmd-option"
179+
id="autocomplete-listbox-result-3"
180+
role="option"
181+
>
182+
<span
183+
class="rmd-list-item__text"
184+
>
185+
American Samoa
186+
</span>
187+
</li>
188+
<li
189+
class="rmd-list-item rmd-list-item--clickable rmd-option"
190+
id="autocomplete-listbox-result-4"
191+
role="option"
192+
>
193+
<span
194+
class="rmd-list-item__text"
195+
>
196+
Arizona
197+
</span>
198+
</li>
199+
<li
200+
class="rmd-list-item rmd-list-item--clickable rmd-option"
201+
id="autocomplete-listbox-result-5"
202+
role="option"
203+
>
204+
<span
205+
class="rmd-list-item__text"
206+
>
207+
Arkansas
208+
</span>
209+
</li>
210+
<div>
211+
After Results
212+
</div>
213+
</ul>
214+
`;
215+
3216
exports[`AutoComplete should handle a normal filter flow 1`] = `
4217
<div>
5218
<div

packages/autocomplete/src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,18 @@ export interface AutoCompleteProps
289289
*```
290290
*/
291291
omitKeys?: readonly string[];
292+
293+
/**
294+
* Any optional children to display before the matched results in the
295+
* autocomplete's menu. This should normally be for any presentational data or
296+
* things that should not be searchable.
297+
*/
298+
beforeResultsChildren?: ReactNode;
299+
300+
/**
301+
* Any optional children to display after the matched results in the
302+
* autocomplete's menu. This should normally be for any presentational data or
303+
* things that should not be searchable.
304+
*/
305+
afterResultsChildren?: ReactNode;
292306
}

0 commit comments

Comments
 (0)