Skip to content

Commit 3a7c41d

Browse files
juliajforestiCopilotdougfabris
authored
feat(fuselage): add AutoComplete component (#1956)
Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Douglas Fabris <devfabris@gmail.com>
1 parent 09ef890 commit 3a7c41d

7 files changed

Lines changed: 381 additions & 25 deletions

File tree

.changeset/moody-corners-sing.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@rocket.chat/fuselage-forms': minor
3+
'@rocket.chat/fuselage': minor
4+
---
5+
6+
feat(fuselage-forms): add `AutoComplete` component

packages/fuselage-forms/src/Field/Field.stories.tsx

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
UrlInput,
1717
MultiSelect,
1818
Slider,
19+
AutoComplete,
1920
} from '../Inputs';
2021

2122
import {
@@ -326,3 +327,96 @@ export const WithSlider: StoryFn<typeof Field> = () => {
326327
</Field>
327328
);
328329
};
330+
331+
export const WithAutoComplete: StoryFn<typeof Field> = () => {
332+
const [filter, setFilter] = useState('');
333+
const [value, setValue] = useState<string>('');
334+
335+
const options = [
336+
{ value: '1', label: 'Option 1' },
337+
{ value: '2', label: 'Option 2' },
338+
{ value: '3', label: 'Option 3' },
339+
{ value: '4', label: 'Option 4' },
340+
{ value: '5', label: 'Option 5' },
341+
];
342+
343+
const handleChange = (newValue: string | string[]) => {
344+
if (typeof newValue === 'string') {
345+
setValue(newValue);
346+
}
347+
};
348+
349+
return (
350+
<Field>
351+
<FieldLabel required>
352+
Example AutoComplete
353+
<FieldLabelInfo title='with extra info in a tooltip' />
354+
</FieldLabel>
355+
<FieldDescription>
356+
You can search and select a single option from a list
357+
</FieldDescription>
358+
<FieldRow>
359+
<AutoComplete
360+
value={value}
361+
filter={filter}
362+
setFilter={setFilter}
363+
options={options}
364+
onChange={handleChange}
365+
placeholder='Search...'
366+
/>
367+
</FieldRow>
368+
<FieldError>You failed to enter a valid value</FieldError>
369+
<FieldRow>
370+
<FieldHint>This should help the user enter a valid value</FieldHint>
371+
<FieldLink href='#'>Link to more information</FieldLink>
372+
</FieldRow>
373+
</Field>
374+
);
375+
};
376+
377+
export const WithAutoCompleteMultiple: StoryFn<typeof Field> = () => {
378+
const [filter, setFilter] = useState('');
379+
const [value, setValue] = useState<string[]>(['1', '3']);
380+
381+
const options = [
382+
{ value: '1', label: 'Option 1' },
383+
{ value: '2', label: 'Option 2' },
384+
{ value: '3', label: 'Option 3' },
385+
{ value: '4', label: 'Option 4' },
386+
{ value: '5', label: 'Option 5' },
387+
];
388+
389+
const handleChange = (newValue: string | string[]) => {
390+
if (Array.isArray(newValue)) {
391+
setValue(newValue);
392+
}
393+
};
394+
395+
return (
396+
<Field>
397+
<FieldLabel required>
398+
Example AutoComplete (Multiple)
399+
<FieldLabelInfo title='with extra info in a tooltip' />
400+
</FieldLabel>
401+
<FieldDescription>
402+
You can search and select multiple options from a list
403+
</FieldDescription>
404+
<FieldRow>
405+
<AutoComplete
406+
multiple
407+
value={value}
408+
filter={filter}
409+
setFilter={setFilter}
410+
options={options}
411+
onChange={handleChange}
412+
placeholder='Search...'
413+
/>
414+
</FieldRow>
415+
<FieldError>You failed to enter a valid value</FieldError>
416+
<FieldRow>
417+
<FieldHint>This should help the user enter a valid value</FieldHint>
418+
<FieldLink href='#'>Link to more information</FieldLink>
419+
</FieldRow>
420+
</Field>
421+
);
422+
};

packages/fuselage-forms/src/Inputs/WrappedInputComponents.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
NumberInput as NumberInputComponent,
1212
TelephoneInput as TelephoneInputComponent,
1313
UrlInput as UrlInputComponent,
14+
AutoComplete as AutoCompleteComponent,
1415
MultiSelect as MultiSelectComponent,
1516
MultiSelectFiltered as MultiSelectFilteredComponent,
1617
Slider as SliderComponent,
@@ -39,6 +40,9 @@ export const UrlInput = withLabelId(UrlInputComponent);
3940
export const Select = withAriaLabelledBy(SelectComponent);
4041

4142
// with aria-labelledby + id for aria-controls
43+
export const AutoComplete = withAriaLabelledByAndId(
44+
AutoCompleteComponent,
45+
) as typeof AutoCompleteComponent;
4246
export const MultiSelect = withAriaLabelledByAndId(MultiSelectComponent);
4347
export const MultiSelectFiltered = withAriaLabelledByAndId(
4448
MultiSelectFilteredComponent,

packages/fuselage-forms/src/__snapshots__/test.spec.tsx.snap

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,239 @@
11
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

3+
exports[`renders WithAutoComplete without crashing 1`] = `
4+
<body>
5+
<div>
6+
<div
7+
class="rcx-box rcx-box--full rcx-field"
8+
>
9+
<span
10+
class="rcx-box rcx-box--full rcx-field__label rcx-label"
11+
id="react-aria-:rj:-label"
12+
>
13+
Example AutoComplete
14+
<span
15+
class="rcx-box rcx-box--full rcx-label__info rcx-css-wcp0mp"
16+
>
17+
<span
18+
hidden=""
19+
>
20+
with extra info in a tooltip
21+
</span>
22+
<i
23+
aria-hidden="true"
24+
class="rcx-box rcx-box--full rcx-icon--name-info-circled rcx-icon"
25+
title="with extra info in a tooltip"
26+
>
27+
28+
</i>
29+
</span>
30+
<span
31+
aria-hidden="true"
32+
class="rcx-box rcx-box--full rcx-label__required rcx-css-b7g1a9"
33+
>
34+
*
35+
</span>
36+
</span>
37+
<span
38+
class="rcx-box rcx-box--full rcx-field__description"
39+
id="react-aria-:rj:-description"
40+
>
41+
You can search and select a single option from a list
42+
</span>
43+
<span
44+
class="rcx-box rcx-box--full rcx-field__row"
45+
>
46+
<div
47+
class="rcx-box rcx-box--full rcx-autocomplete rcx-css-t3n91h"
48+
>
49+
<div
50+
class="rcx-box rcx-box--full rcx-css-6d871f"
51+
role="group"
52+
>
53+
<input
54+
aria-describedby="react-aria-:rj:-description react-aria-:rj:-error react-aria-:rj:-hint"
55+
aria-invalid="true"
56+
aria-labelledby="react-aria-:rj:-label"
57+
class="rcx-box rcx-box--full rcx-box--animated rcx-input-box--undecorated rcx-input-box rcx-css-trljwa rcx-css-rcil7k"
58+
id="react-aria-:rj:"
59+
placeholder="Search..."
60+
value=""
61+
/>
62+
</div>
63+
<div
64+
class="rcx-box rcx-box--full rcx-autocomplete__addon"
65+
>
66+
<i
67+
aria-hidden="true"
68+
class="rcx-box rcx-box--full rcx-icon--name-magnifier rcx-icon rcx-css-1wz6xj9"
69+
>
70+
71+
</i>
72+
</div>
73+
</div>
74+
</span>
75+
<span
76+
class="rcx-box rcx-box--full rcx-field__error"
77+
id="react-aria-:rj:-error"
78+
role="alert"
79+
>
80+
You failed to enter a valid value
81+
</span>
82+
<span
83+
class="rcx-box rcx-box--full rcx-field__row"
84+
>
85+
<span
86+
class="rcx-box rcx-box--full rcx-field__hint"
87+
id="react-aria-:rj:-hint"
88+
>
89+
This should help the user enter a valid value
90+
</span>
91+
<a
92+
class="rcx-box rcx-box--full rcx-field__link"
93+
href="#"
94+
>
95+
Link to more information
96+
</a>
97+
</span>
98+
</div>
99+
</div>
100+
</body>
101+
`;
102+
103+
exports[`renders WithAutoCompleteMultiple without crashing 1`] = `
104+
<body>
105+
<div>
106+
<div
107+
class="rcx-box rcx-box--full rcx-field"
108+
>
109+
<span
110+
class="rcx-box rcx-box--full rcx-field__label rcx-label"
111+
id="react-aria-:rk:-label"
112+
>
113+
Example AutoComplete (Multiple)
114+
<span
115+
class="rcx-box rcx-box--full rcx-label__info rcx-css-wcp0mp"
116+
>
117+
<span
118+
hidden=""
119+
>
120+
with extra info in a tooltip
121+
</span>
122+
<i
123+
aria-hidden="true"
124+
class="rcx-box rcx-box--full rcx-icon--name-info-circled rcx-icon"
125+
title="with extra info in a tooltip"
126+
>
127+
128+
</i>
129+
</span>
130+
<span
131+
aria-hidden="true"
132+
class="rcx-box rcx-box--full rcx-label__required rcx-css-b7g1a9"
133+
>
134+
*
135+
</span>
136+
</span>
137+
<span
138+
class="rcx-box rcx-box--full rcx-field__description"
139+
id="react-aria-:rk:-description"
140+
>
141+
You can search and select multiple options from a list
142+
</span>
143+
<span
144+
class="rcx-box rcx-box--full rcx-field__row"
145+
>
146+
<div
147+
class="rcx-box rcx-box--full rcx-autocomplete rcx-css-t3n91h"
148+
>
149+
<div
150+
class="rcx-box rcx-box--full rcx-css-6d871f"
151+
role="group"
152+
>
153+
<input
154+
aria-describedby="react-aria-:rk:-description react-aria-:rk:-error react-aria-:rk:-hint"
155+
aria-invalid="true"
156+
aria-labelledby="react-aria-:rk:-label"
157+
class="rcx-box rcx-box--full rcx-box--animated rcx-input-box--undecorated rcx-input-box rcx-css-trljwa rcx-css-rcil7k"
158+
id="react-aria-:rk:"
159+
placeholder="Search..."
160+
value=""
161+
/>
162+
<button
163+
class="rcx-box rcx-chip rcx-css-trljwa"
164+
type="button"
165+
value="1"
166+
>
167+
<span
168+
class="rcx-box rcx-chip__text rcx-css-trljwa"
169+
>
170+
Option 1
171+
</span>
172+
<i
173+
aria-hidden="true"
174+
class="rcx-box rcx-box--full rcx-icon--name-cross rcx-icon rcx-css-trljwa rcx-css-1wv1vf9"
175+
>
176+
177+
</i>
178+
</button>
179+
<button
180+
class="rcx-box rcx-chip rcx-css-trljwa"
181+
type="button"
182+
value="3"
183+
>
184+
<span
185+
class="rcx-box rcx-chip__text rcx-css-trljwa"
186+
>
187+
Option 3
188+
</span>
189+
<i
190+
aria-hidden="true"
191+
class="rcx-box rcx-box--full rcx-icon--name-cross rcx-icon rcx-css-trljwa rcx-css-1wv1vf9"
192+
>
193+
194+
</i>
195+
</button>
196+
</div>
197+
<div
198+
class="rcx-box rcx-box--full rcx-autocomplete__addon"
199+
>
200+
<i
201+
aria-hidden="true"
202+
class="rcx-box rcx-box--full rcx-icon--name-magnifier rcx-icon rcx-css-1wz6xj9"
203+
>
204+
205+
</i>
206+
</div>
207+
</div>
208+
</span>
209+
<span
210+
class="rcx-box rcx-box--full rcx-field__error"
211+
id="react-aria-:rk:-error"
212+
role="alert"
213+
>
214+
You failed to enter a valid value
215+
</span>
216+
<span
217+
class="rcx-box rcx-box--full rcx-field__row"
218+
>
219+
<span
220+
class="rcx-box rcx-box--full rcx-field__hint"
221+
id="react-aria-:rk:-hint"
222+
>
223+
This should help the user enter a valid value
224+
</span>
225+
<a
226+
class="rcx-box rcx-box--full rcx-field__link"
227+
href="#"
228+
>
229+
Link to more information
230+
</a>
231+
</span>
232+
</div>
233+
</div>
234+
</body>
235+
`;
236+
3237
exports[`renders WithCheckbox without crashing 1`] = `
4238
<body>
5239
<div>

packages/fuselage-forms/src/test.spec.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const {
1919
WithTextArea,
2020
WithMultiSelect,
2121
WithSlider,
22+
WithAutoComplete,
23+
WithAutoCompleteMultiple,
2224
...restStories
2325
} = composedStories;
2426

0 commit comments

Comments
 (0)