1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
import { forwardRef, type ForwardRefRenderFunction, useId } from 'react';
import { useIntl } from 'react-intl';
import { type FormSubmitHandler, useForm } from '../../../../utils/hooks';
import {
Button,
Form,
type FormProps,
Icon,
Input,
Label,
} from '../../../atoms';
import { LabelledField } from '../../../molecules';
import styles from './search-form.module.scss';
export type SearchFormData = { query: string };
export type SearchFormSubmit = FormSubmitHandler<SearchFormData>;
export type SearchFormProps = Omit<FormProps, 'children' | 'onSubmit'> & {
/**
* Should the label be visually hidden?
*
* @default false
*/
isLabelHidden?: boolean;
/**
* A callback function to handle search form submit.
*/
onSubmit?: SearchFormSubmit;
};
const SearchFormWithRef: ForwardRefRenderFunction<
HTMLInputElement,
SearchFormProps
> = ({ className = '', isLabelHidden = false, onSubmit, ...props }, ref) => {
const intl = useIntl();
const { values, submit, submitStatus, update } = useForm<SearchFormData>({
initialValues: { query: '' },
submitHandler: onSubmit,
});
const id = useId();
const formClass = [
styles.wrapper,
styles[isLabelHidden ? 'wrapper--no-label' : 'wrapper--has-label'],
className,
].join(' ');
const labels = {
button: intl.formatMessage({
defaultMessage: 'Search',
description: 'SearchForm: button accessible name',
id: 'WMqQrv',
}),
field: intl.formatMessage({
defaultMessage: 'Search for:',
description: 'SearchForm: field accessible label',
id: 'X8oujO',
}),
};
return (
<Form {...props} className={formClass} onSubmit={submit}>
<LabelledField
className={styles.field}
field={
<Input
className={styles.input}
id={id}
// eslint-disable-next-line react/jsx-no-literals
name="query"
onChange={update}
ref={ref}
// eslint-disable-next-line react/jsx-no-literals
type="search"
value={values.query}
/>
}
label={
<Label htmlFor={id} isHidden={isLabelHidden}>
{labels.field}
</Label>
}
/>
<Button
aria-label={labels.button}
className={styles.btn}
isLoading={submitStatus === 'PENDING'}
// eslint-disable-next-line react/jsx-no-literals
kind="neutral"
// eslint-disable-next-line react/jsx-no-literals
shape="initial"
type="submit"
>
<Icon
aria-hidden
className={styles.icon}
// eslint-disable-next-line react/jsx-no-literals
shape="magnifying-glass"
// eslint-disable-next-line react/jsx-no-literals
size="lg"
/>
</Button>
</Form>
);
};
/**
* SearchForm component
*
* Render a search form.
*/
export const SearchForm = forwardRef(SearchFormWithRef);
|