aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules/forms/radio-group/radio-group.tsx
blob: 0ca4dac5af947970463fba25ae8da114b964d8b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { ForwardRefRenderFunction, forwardRef } from 'react';
import {
  Fieldset,
  FieldsetProps,
  Label,
  LabelProps,
  Radio,
  RadioProps,
} from '../../../atoms';
import { LabelledField } from '../labelled-field';
import styles from './radio-group.module.scss';

export type RadioGroupItem = {
  /**
   * The item id.
   */
  id: string;
  /**
   * Should the item be disabled?
   */
  isDisabled?: boolean;
  /**
   * The item label.
   */
  label: LabelProps['children'];
  /**
   * The item value.
   */
  value: string;
};

export type RadioGroupProps = Omit<FieldsetProps, 'children' | 'role'> & {
  /**
   * Should we display the radio buttons inlined?
   *
   * @default false
   */
  isInline?: boolean;
  /**
   * The radio group name.
   */
  name: string;
  /**
   * A function to handle selection change.
   */
  onSwitch?: RadioProps['onChange'];
  /**
   * The options.
   */
  options: RadioGroupItem[];
  /**
   * The selected value. It should match a RadioGroupItem value or be undefined.
   */
  value?: RadioGroupItem['value'];
};

const RadioGroupWithRef: ForwardRefRenderFunction<
  HTMLFieldSetElement,
  RadioGroupProps
> = (
  {
    className = '',
    isInline = false,
    name,
    onSwitch,
    options,
    value,
    ...props
  },
  ref
) => {
  const layoutModifier = isInline ? styles['group--inline'] : '';
  const groupClass = `${layoutModifier} ${className}`;

  return (
    <Fieldset
      {...props}
      className={groupClass}
      isInline={isInline}
      ref={ref}
      role="radiogroup"
    >
      {options.map((option) => (
        <LabelledField
          className={styles.option}
          field={
            <Radio
              id={option.id}
              isChecked={value === option.value}
              name={name}
              onChange={onSwitch}
              value={option.value}
            />
          }
          isInline
          isReversedOrder
          key={option.id}
          label={<Label htmlFor={option.id}>{option.label}</Label>}
        />
      ))}
    </Fieldset>
  );
};

/**
 * RadioGroup component
 *
 * Render a group of labelled radio buttons.
 */
export const RadioGroup = forwardRef(RadioGroupWithRef);