Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / pass / components / Form / Field / RadioButtonGroupField.tsx
blob517b07f78310b665541cb4938bad9ba19acf6f1e
1 import { Children, type FC, type ReactElement, type ReactNode, cloneElement } from 'react';
3 import { type FieldProps } from 'formik';
5 import { Icon, type IconName, InputButton, InputFieldTwo } from '@proton/components';
6 import { type InputFieldProps } from '@proton/components/components/v2/field/InputField';
7 import type { MaybeArray } from '@proton/pass/types';
8 import clsx from '@proton/utils/clsx';
10 import { useFieldControl } from '../../../hooks/useFieldControl';
11 import type { RadioValue } from './RadioGroupField';
13 import './RadioButtonGroupField.scss';
15 type BaseRadioProps<T> = {
16     checked?: boolean;
17     disabled?: boolean;
18     id?: string;
19     name?: string;
20     onChange?: (value: T) => void;
21     value: T;
24 type RadioButtonProps<T> = BaseRadioProps<T> & { color?: string; icon?: IconName };
26 export const RadioButton = <T,>({ onChange, id, checked, value, name, color, icon }: RadioButtonProps<T>) => {
27     return (
28         <InputButton
29             type="radio"
30             id={id}
31             name={name}
32             checked={checked}
33             onChange={(e) => e.target.checked && onChange?.(value)}
34             labelProps={{
35                 className: 'pass-radio-group--button',
36                 style: { '--radio-button-background': color ? `rgb(${color})` : 'var(--background-weak)' },
37             }}
38         >
39             {icon && <Icon name={icon} size={5} />}
40         </InputButton>
41     );
44 type RadioLabelledButtonProps<T> = BaseRadioProps<T> & { children: MaybeArray<ReactNode> };
46 export const RadioLabelledButton = <T extends RadioValue>({
47     id,
48     name,
49     disabled,
50     value,
51     checked,
52     onChange,
53     children,
54 }: RadioLabelledButtonProps<T>) => {
55     return (
56         <label
57             htmlFor={id}
58             className={clsx([
59                 'pass-radio-group--labelled-button w-full expand-click-area relative',
60                 disabled && 'opacity-50 pointer-events-none',
61             ])}
62         >
63             <input
64                 id={id}
65                 type="radio"
66                 className="radio"
67                 name={name}
68                 disabled={disabled}
69                 value={value}
70                 onChange={(e) => e.target.checked && onChange?.(value)}
71             />
72             <div className="flex items-center gap-x-3 py-4">
73                 {children}
74                 {checked && <Icon name="checkmark" size={6} color="var(--interaction-norm)" />}
75             </div>
76         </label>
77     );
80 type RadioButtonGroupProps<T> = {
81     children: ReactElement<BaseRadioProps<T>>[];
82     className?: string;
83     name: string;
84     onChange?: (value: T) => void;
85     value?: T;
88 export const RadioButtonGroup = <T extends RadioValue>(props: RadioButtonGroupProps<T>) => {
89     const radioButtons = Children.map(props.children, (child, id) => {
90         return cloneElement(child, {
91             checked: props.value === child.props.value,
92             id: `${props.name}-${id}`,
93             name: props.name,
94             onChange: props.onChange,
95         });
96     });
98     return <div className={clsx('flex', props.className)}>{radioButtons}</div>;
101 type RadioButtonGroupFieldProps = FieldProps & InputFieldProps<typeof RadioButtonGroup>;
103 export const RadioButtonGroupField: FC<RadioButtonGroupFieldProps> = ({ field, form, meta, onChange, ...props }) => {
104     const { error } = useFieldControl({ field, form, meta });
106     return (
107         <InputFieldTwo<typeof RadioButtonGroup>
108             as={RadioButtonGroup}
109             assistContainerClassName="empty:hidden"
110             error={error}
111             {...field}
112             {...props}
113             onChange={async (value: RadioValue) => {
114                 onChange?.(value);
115                 await form.setFieldValue(field.name, value);
116             }}
117         />
118     );