"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-7542/react/features/base/ui/components/web/Input.tsx" (21 Sep 2023, 8754 Bytes) of package /linux/misc/jitsi-meet-7542.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TSX (TypeScript with React) source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "Input.tsx": jitsi-meet_8719_vs_jitsi-meet_8922.

    1 import React, { useCallback } from 'react';
    2 import TextareaAutosize from 'react-textarea-autosize';
    3 import { makeStyles } from 'tss-react/mui';
    4 
    5 import { isMobileBrowser } from '../../../environment/utils';
    6 import Icon from '../../../icons/components/Icon';
    7 import { IconCloseCircle } from '../../../icons/svg';
    8 import { withPixelLineHeight } from '../../../styles/functions.web';
    9 import { IInputProps } from '../types';
   10 
   11 interface IProps extends IInputProps {
   12     accessibilityLabel?: string;
   13     autoComplete?: string;
   14     autoFocus?: boolean;
   15     bottomLabel?: string;
   16     className?: string;
   17     iconClick?: () => void;
   18 
   19     /**
   20      * The id to set on the input element.
   21      * This is required because we need it internally to tie the input to its
   22      * info (label, error) so that screen reader users don't get lost.
   23      */
   24     id: string;
   25     maxLength?: number;
   26     maxRows?: number;
   27     maxValue?: number;
   28     minRows?: number;
   29     minValue?: number;
   30     mode?: 'text' | 'none' | 'decimal' | 'numeric' | 'tel' | 'search' | ' email' | 'url';
   31     name?: string;
   32     onBlur?: (e: any) => void;
   33     onFocus?: (event: React.FocusEvent) => void;
   34     onKeyPress?: (e: React.KeyboardEvent) => void;
   35     readOnly?: boolean;
   36     required?: boolean;
   37     testId?: string;
   38     textarea?: boolean;
   39     type?: 'text' | 'email' | 'number' | 'password';
   40 }
   41 
   42 const useStyles = makeStyles()(theme => {
   43     return {
   44         inputContainer: {
   45             display: 'flex',
   46             flexDirection: 'column'
   47         },
   48 
   49         label: {
   50             color: theme.palette.text01,
   51             ...withPixelLineHeight(theme.typography.bodyShortRegular),
   52             marginBottom: theme.spacing(2),
   53 
   54             '&.is-mobile': {
   55                 ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
   56             }
   57         },
   58 
   59         fieldContainer: {
   60             position: 'relative',
   61             display: 'flex'
   62         },
   63 
   64         input: {
   65             backgroundColor: theme.palette.ui03,
   66             background: theme.palette.ui03,
   67             color: theme.palette.text01,
   68             ...withPixelLineHeight(theme.typography.bodyShortRegular),
   69             padding: '10px 16px',
   70             borderRadius: theme.shape.borderRadius,
   71             border: 0,
   72             height: '40px',
   73             boxSizing: 'border-box',
   74             width: '100%',
   75 
   76             '&::placeholder': {
   77                 color: theme.palette.text02
   78             },
   79 
   80             '&:focus': {
   81                 outline: 0,
   82                 boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
   83             },
   84 
   85             '&:disabled': {
   86                 color: theme.palette.text03
   87             },
   88 
   89             '&.is-mobile': {
   90                 height: '48px',
   91                 padding: '13px 16px',
   92                 ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
   93             },
   94 
   95             '&.icon-input': {
   96                 paddingLeft: '46px'
   97             },
   98 
   99             '&.error': {
  100                 boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
  101             }
  102         },
  103 
  104         'input::-webkit-outer-spin-button, input::-webkit-inner-spin-button': {
  105             '-webkit-appearance': 'none',
  106             margin: 0
  107         },
  108 
  109         'input[type=number]': {
  110             '-moz-appearance': 'textfield'
  111         },
  112 
  113         icon: {
  114             position: 'absolute',
  115             top: '50%',
  116             transform: 'translateY(-50%)',
  117             left: '16px'
  118         },
  119 
  120         iconClickable: {
  121             cursor: 'pointer'
  122         },
  123 
  124         clearableInput: {
  125             paddingRight: '46px'
  126         },
  127 
  128         clearButton: {
  129             position: 'absolute',
  130             right: '16px',
  131             top: '10px',
  132             cursor: 'pointer',
  133             backgroundColor: theme.palette.action03,
  134             border: 0,
  135             padding: 0
  136         },
  137 
  138         bottomLabel: {
  139             marginTop: theme.spacing(2),
  140             ...withPixelLineHeight(theme.typography.labelRegular),
  141             color: theme.palette.text02,
  142 
  143             '&.is-mobile': {
  144                 ...withPixelLineHeight(theme.typography.bodyShortRegular)
  145             },
  146 
  147             '&.error': {
  148                 color: theme.palette.textError
  149             }
  150         }
  151     };
  152 });
  153 
  154 const Input = React.forwardRef<any, IProps>(({
  155     accessibilityLabel,
  156     autoComplete,
  157     autoFocus,
  158     bottomLabel,
  159     className,
  160     clearable = false,
  161     disabled,
  162     error,
  163     icon,
  164     iconClick,
  165     id,
  166     label,
  167     maxValue,
  168     maxLength,
  169     maxRows,
  170     minValue,
  171     minRows,
  172     mode,
  173     name,
  174     onBlur,
  175     onChange,
  176     onFocus,
  177     onKeyPress,
  178     placeholder,
  179     readOnly = false,
  180     required,
  181     testId,
  182     textarea = false,
  183     type = 'text',
  184     value
  185 }: IProps, ref) => {
  186     const { classes: styles, cx } = useStyles();
  187     const isMobile = isMobileBrowser();
  188 
  189     const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
  190         onChange?.(e.target.value), []);
  191 
  192     const clearInput = useCallback(() => onChange?.(''), []);
  193 
  194     return (
  195         <div className = { cx(styles.inputContainer, className) }>
  196             {label && <label
  197                 className = { cx(styles.label, isMobile && 'is-mobile') }
  198                 htmlFor = { id } >
  199                 {label}
  200             </label>}
  201             <div className = { styles.fieldContainer }>
  202                 {icon && <Icon
  203                     { ...(iconClick ? { tabIndex: 0 } : {}) }
  204                     className = { cx(styles.icon, iconClick && styles.iconClickable) }
  205                     onClick = { iconClick }
  206                     size = { 20 }
  207                     src = { icon } />}
  208                 {textarea ? (
  209                     <TextareaAutosize
  210                         aria-label = { accessibilityLabel }
  211                         autoComplete = { autoComplete }
  212                         autoFocus = { autoFocus }
  213                         className = { cx(styles.input, isMobile && 'is-mobile',
  214                             error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }
  215                         disabled = { disabled }
  216                         id = { id }
  217                         maxLength = { maxLength }
  218                         maxRows = { maxRows }
  219                         minRows = { minRows }
  220                         name = { name }
  221                         onChange = { handleChange }
  222                         onKeyPress = { onKeyPress }
  223                         placeholder = { placeholder }
  224                         readOnly = { readOnly }
  225                         ref = { ref }
  226                         required = { required }
  227                         value = { value } />
  228                 ) : (
  229                     <input
  230                         aria-describedby = { bottomLabel ? `${id}-description` : undefined }
  231                         aria-label = { accessibilityLabel }
  232                         autoComplete = { autoComplete }
  233                         autoFocus = { autoFocus }
  234                         className = { cx(styles.input, isMobile && 'is-mobile',
  235                             error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }
  236                         data-testid = { testId }
  237                         disabled = { disabled }
  238                         id = { id }
  239                         { ...(mode ? { inputmode: mode } : {}) }
  240                         { ...(type === 'number' ? { max: maxValue } : {}) }
  241                         maxLength = { maxLength }
  242                         { ...(type === 'number' ? { min: minValue } : {}) }
  243                         name = { name }
  244                         onBlur = { onBlur }
  245                         onChange = { handleChange }
  246                         onFocus = { onFocus }
  247                         onKeyPress = { onKeyPress }
  248                         placeholder = { placeholder }
  249                         readOnly = { readOnly }
  250                         ref = { ref }
  251                         required = { required }
  252                         type = { type }
  253                         value = { value } />
  254                 )}
  255                 {clearable && !disabled && value !== '' && <button className = { styles.clearButton }>
  256                     <Icon
  257                         onClick = { clearInput }
  258                         size = { 20 }
  259                         src = { IconCloseCircle } />
  260                 </button>}
  261             </div>
  262             {bottomLabel && (
  263                 <span
  264                     className = { cx(styles.bottomLabel, isMobile && 'is-mobile', error && 'error') }
  265                     id = { `${id}-description` }>
  266                     {bottomLabel}
  267                 </span>
  268             )}
  269         </div>
  270     );
  271 });
  272 
  273 export default Input;