Signal-Desktop/ts/components/SearchInput.tsx

99 lines
2.7 KiB
TypeScript
Raw Normal View History

2022-02-14 17:57:11 +00:00
// Copyright 2021-2022 Signal Messenger, LLC
2021-05-11 00:50:43 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
2022-02-14 17:57:11 +00:00
import type {
ChangeEvent,
FocusEventHandler,
KeyboardEvent,
ReactNode,
} from 'react';
import React, { forwardRef } from 'react';
2022-02-14 17:57:11 +00:00
import classNames from 'classnames';
import type { LocalizerType } from '../types/Util';
2021-05-11 00:50:43 +00:00
import { getClassNamesFor } from '../util/getClassNamesFor';
export type PropTypes = {
2022-02-14 17:57:11 +00:00
readonly children?: ReactNode;
2021-05-11 00:50:43 +00:00
readonly disabled?: boolean;
2022-02-14 17:57:11 +00:00
readonly label?: string;
readonly hasSearchIcon?: boolean;
readonly i18n: LocalizerType;
2021-05-11 00:50:43 +00:00
readonly moduleClassName?: string;
2022-02-14 17:57:11 +00:00
readonly onClear?: () => unknown;
readonly onBlur?: FocusEventHandler<HTMLInputElement>;
2021-05-11 00:50:43 +00:00
readonly onChange: (ev: ChangeEvent<HTMLInputElement>) => unknown;
readonly onKeyDown?: (ev: KeyboardEvent<HTMLInputElement>) => unknown;
readonly placeholder: string;
readonly value: string;
};
const BASE_CLASS_NAME = 'module-SearchInput';
export const SearchInput = forwardRef<HTMLInputElement, PropTypes>(
(
{
2022-02-14 17:57:11 +00:00
children,
2021-05-11 00:50:43 +00:00
disabled = false,
2022-02-14 17:57:11 +00:00
hasSearchIcon = true,
i18n,
label,
2021-05-11 00:50:43 +00:00
moduleClassName,
2022-02-14 17:57:11 +00:00
onClear,
onBlur,
2021-05-11 00:50:43 +00:00
onChange,
onKeyDown,
placeholder,
value,
},
ref
) => {
const getClassName = getClassNamesFor(BASE_CLASS_NAME, moduleClassName);
return (
<div className={getClassName('__container')}>
2022-02-14 17:57:11 +00:00
{hasSearchIcon && <i className={getClassName('__icon')} />}
{children}
2021-05-11 00:50:43 +00:00
<input
2022-02-14 17:57:11 +00:00
aria-label={label || i18n('search')}
className={classNames(
getClassName('__input'),
value && getClassName('__input--with-text'),
children && getClassName('__input--with-children')
)}
2021-05-11 00:50:43 +00:00
dir="auto"
disabled={disabled}
2022-02-14 17:57:11 +00:00
onBlur={onBlur}
2021-05-11 00:50:43 +00:00
onChange={onChange}
2022-02-14 17:57:11 +00:00
onKeyDown={event => {
const { ctrlKey, key } = event;
// On Linux, this key combo selects all text.
if (window.platform === 'linux' && ctrlKey && key === '/') {
event.preventDefault();
event.stopPropagation();
} else if (key === 'Escape' && onClear) {
onClear();
event.preventDefault();
event.stopPropagation();
}
onKeyDown?.(event);
}}
2021-05-11 00:50:43 +00:00
placeholder={placeholder}
ref={ref}
type="text"
value={value}
/>
2022-02-14 17:57:11 +00:00
{value && onClear && (
<button
aria-label={i18n('cancel')}
className={getClassName('__cancel')}
onClick={onClear}
tabIndex={-1}
type="button"
/>
)}
2021-05-11 00:50:43 +00:00
</div>
);
}
);