signal-desktop/ts/components/SearchInput.tsx

104 lines
2.8 KiB
TypeScript
Raw Normal View History

2023-01-03 11:55:46 -08:00
// Copyright 2021 Signal Messenger, LLC
2021-05-10 20:50:43 -04:00
// SPDX-License-Identifier: AGPL-3.0-only
2022-02-14 12:57:11 -05:00
import type {
ChangeEvent,
FocusEventHandler,
KeyboardEvent,
ReactNode,
} from 'react';
import React, { forwardRef } from 'react';
2022-02-14 12:57:11 -05:00
import classNames from 'classnames';
import type { LocalizerType } from '../types/Util';
2021-05-10 20:50:43 -04:00
import { getClassNamesFor } from '../util/getClassNamesFor';
export type PropTypes = Readonly<{
children?: ReactNode;
disabled?: boolean;
label?: string;
hasSearchIcon?: boolean;
i18n: LocalizerType;
moduleClassName?: string;
onClear?: () => unknown;
onBlur?: FocusEventHandler<HTMLInputElement>;
onChange: (ev: ChangeEvent<HTMLInputElement>) => unknown;
onKeyDown?: (ev: KeyboardEvent<HTMLInputElement>) => unknown;
placeholder: string;
value: string;
description?: string;
}>;
2021-05-10 20:50:43 -04:00
const BASE_CLASS_NAME = 'module-SearchInput';
export const SearchInput = forwardRef<HTMLInputElement, PropTypes>(
2022-11-17 16:45:19 -08:00
function SearchInputInner(
2021-05-10 20:50:43 -04:00
{
2022-02-14 12:57:11 -05:00
children,
2021-05-10 20:50:43 -04:00
disabled = false,
2022-02-14 12:57:11 -05:00
hasSearchIcon = true,
i18n,
label,
2021-05-10 20:50:43 -04:00
moduleClassName,
2022-02-14 12:57:11 -05:00
onClear,
onBlur,
2021-05-10 20:50:43 -04:00
onChange,
onKeyDown,
placeholder,
value,
description,
2021-05-10 20:50:43 -04:00
},
ref
2022-11-17 16:45:19 -08:00
) {
2021-05-10 20:50:43 -04:00
const getClassName = getClassNamesFor(BASE_CLASS_NAME, moduleClassName);
return (
2023-05-09 11:52:03 -04:00
<div className={getClassName('__container')} data-supertab>
2022-02-14 12:57:11 -05:00
{hasSearchIcon && <i className={getClassName('__icon')} />}
{children}
2021-05-10 20:50:43 -04:00
<input
2023-03-29 17:03:25 -07:00
aria-label={label || i18n('icu:search')}
2022-02-14 12:57:11 -05:00
className={classNames(
getClassName('__input'),
value && getClassName('__input--with-text'),
children && getClassName('__input--with-children')
)}
2021-05-10 20:50:43 -04:00
dir="auto"
disabled={disabled}
2022-02-14 12:57:11 -05:00
onBlur={onBlur}
2021-05-10 20:50:43 -04:00
onChange={onChange}
2022-02-14 12:57:11 -05: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-10 20:50:43 -04:00
placeholder={placeholder}
ref={ref}
type="text"
value={value}
/>
2022-02-14 12:57:11 -05:00
{value && onClear && (
<button
2023-03-29 17:03:25 -07:00
aria-label={i18n('icu:cancel')}
2022-02-14 12:57:11 -05:00
className={getClassName('__cancel')}
onClick={onClear}
tabIndex={-1}
type="button"
/>
)}
{description && (
<div className={getClassName('__description')}>{description}</div>
)}
2021-05-10 20:50:43 -04:00
</div>
);
}
);