mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Convert Form Components to TypeScript
Co-authored-by: Mark McDowall <mark@mcdowall.ca> Remove defaultProps from TypeScript components (cherry picked from commit a90c13e86f798841cb6db038bb6b6d1408a00585) Fix multi-select checkboxes not appearing (cherry picked from commit e199710c15fbfa643a9f71c7a20f70b1722d0df6)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { SyntheticEvent, useCallback, useEffect, useRef } from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import { Kind } from 'Helpers/Props/kinds';
|
||||
import { CheckInputChanged } from 'typings/inputs';
|
||||
import FormInputHelpText from './FormInputHelpText';
|
||||
import styles from './CheckInput.css';
|
||||
|
||||
interface ChangeEvent<T = Element> extends SyntheticEvent<T, MouseEvent> {
|
||||
target: EventTarget & T;
|
||||
}
|
||||
|
||||
interface CheckInputProps {
|
||||
className?: string;
|
||||
containerClassName?: string;
|
||||
name: string;
|
||||
checkedValue?: boolean;
|
||||
uncheckedValue?: boolean;
|
||||
value?: string | boolean | null;
|
||||
helpText?: string;
|
||||
helpTextWarning?: string;
|
||||
isDisabled?: boolean;
|
||||
kind?: Extract<Kind, keyof typeof styles>;
|
||||
onChange: (changes: CheckInputChanged) => void;
|
||||
}
|
||||
|
||||
function CheckInput(props: CheckInputProps) {
|
||||
const {
|
||||
className = styles.input,
|
||||
containerClassName = styles.container,
|
||||
name,
|
||||
value,
|
||||
checkedValue = true,
|
||||
uncheckedValue = false,
|
||||
helpText,
|
||||
helpTextWarning,
|
||||
isDisabled,
|
||||
kind = 'primary',
|
||||
onChange,
|
||||
} = props;
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const isChecked = value === checkedValue;
|
||||
const isUnchecked = value === uncheckedValue;
|
||||
const isIndeterminate = !isChecked && !isUnchecked;
|
||||
const isCheckClass: keyof typeof styles = `${kind}IsChecked`;
|
||||
|
||||
const toggleChecked = useCallback(
|
||||
(checked: boolean, shiftKey: boolean) => {
|
||||
const newValue = checked ? checkedValue : uncheckedValue;
|
||||
|
||||
if (value !== newValue) {
|
||||
onChange({
|
||||
name,
|
||||
value: newValue,
|
||||
shiftKey,
|
||||
});
|
||||
}
|
||||
},
|
||||
[name, value, checkedValue, uncheckedValue, onChange]
|
||||
);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(event: SyntheticEvent<HTMLElement, MouseEvent>) => {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shiftKey = event.nativeEvent.shiftKey;
|
||||
const checked = !(inputRef.current?.checked ?? false);
|
||||
|
||||
event.preventDefault();
|
||||
toggleChecked(checked, shiftKey);
|
||||
},
|
||||
[isDisabled, toggleChecked]
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const checked = event.target.checked;
|
||||
const shiftKey = event.nativeEvent.shiftKey;
|
||||
|
||||
toggleChecked(checked, shiftKey);
|
||||
},
|
||||
[toggleChecked]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputRef.current.indeterminate =
|
||||
value !== uncheckedValue && value !== checkedValue;
|
||||
}, [value, uncheckedValue, checkedValue]);
|
||||
|
||||
return (
|
||||
<div className={containerClassName}>
|
||||
<label className={styles.label} onClick={handleClick}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
className={styles.checkbox}
|
||||
type="checkbox"
|
||||
name={name}
|
||||
checked={isChecked}
|
||||
disabled={isDisabled}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
className,
|
||||
isChecked ? styles[isCheckClass] : styles.isNotChecked,
|
||||
isIndeterminate && styles.isIndeterminate,
|
||||
isDisabled && styles.isDisabled
|
||||
)}
|
||||
>
|
||||
{isChecked ? <Icon name={icons.CHECK} /> : null}
|
||||
|
||||
{isIndeterminate ? <Icon name={icons.CHECK_INDETERMINATE} /> : null}
|
||||
</div>
|
||||
|
||||
{helpText ? (
|
||||
<FormInputHelpText className={styles.helpText} text={helpText} />
|
||||
) : null}
|
||||
|
||||
{!helpText && helpTextWarning ? (
|
||||
<FormInputHelpText
|
||||
className={styles.helpText}
|
||||
text={helpTextWarning}
|
||||
isWarning={true}
|
||||
/>
|
||||
) : null}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CheckInput;
|
||||
Reference in New Issue
Block a user