aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/molecules/forms/switch/switch.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/molecules/forms/switch/switch.tsx')
-rw-r--r--src/components/molecules/forms/switch/switch.tsx132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/components/molecules/forms/switch/switch.tsx b/src/components/molecules/forms/switch/switch.tsx
new file mode 100644
index 0000000..d340a0c
--- /dev/null
+++ b/src/components/molecules/forms/switch/switch.tsx
@@ -0,0 +1,132 @@
+import type { FC, ChangeEventHandler, ReactNode, ReactElement } from 'react';
+import {
+ Fieldset,
+ type FieldsetProps,
+ LabelProps,
+ RadioProps,
+ Label,
+ Radio,
+} from '../../../atoms';
+import styles from './switch.module.scss';
+import { TooltipProps } from '../../tooltip';
+
+type SwitchItemProps = Omit<LabelProps, 'children' | 'htmlFor' | 'isRequired'> &
+ Pick<RadioProps, 'isDisabled' | 'name'> & {
+ /**
+ * The item id.
+ */
+ id: string;
+ /**
+ * Is the item selected?
+ */
+ isSelected?: boolean;
+ /**
+ * The label used to describe the switch item.
+ */
+ label: ReactNode;
+ /**
+ * The event handler on value change.
+ */
+ onSwitch: ChangeEventHandler<HTMLInputElement>;
+ /**
+ * The item value.
+ */
+ value: string;
+ };
+
+/**
+ * SwitchItem component.
+ */
+const SwitchItem: FC<SwitchItemProps> = ({
+ className = '',
+ id,
+ isDisabled = false,
+ isSelected = false,
+ label,
+ name,
+ onSwitch,
+ value,
+ ...props
+}) => {
+ const selectedItemClass = isSelected ? styles['item--selected'] : '';
+ const disabledItemClass = isDisabled ? styles['item--disabled'] : '';
+ const itemClass = `${styles.item} ${selectedItemClass} ${disabledItemClass} ${className}`;
+
+ return (
+ <Label {...props} className={itemClass} htmlFor={id}>
+ <Radio
+ className={styles.radio}
+ id={id}
+ isChecked={isSelected}
+ isDisabled={isDisabled}
+ isHidden
+ name={name}
+ onChange={onSwitch}
+ value={value}
+ />
+ <span className={styles.label}>{label}</span>
+ </Label>
+ );
+};
+
+export type SwitchOption = Pick<SwitchItemProps, 'id' | 'label' | 'value'>;
+
+export type SwitchProps = Omit<FieldsetProps, 'children'> & {
+ /**
+ * The switch items.
+ */
+ items: [SwitchOption, SwitchOption];
+ /**
+ * The switch group name.
+ */
+ name: string;
+ /**
+ * A function to handle selection change.
+ */
+ onSwitch: ChangeEventHandler<HTMLInputElement>;
+ /**
+ * A tooltip to display before switch options.
+ */
+ tooltip?: ReactElement<TooltipProps>;
+ /**
+ * The selected item value.
+ */
+ value: SwitchOption['value'];
+};
+
+/**
+ * Switch component.
+ */
+export const Switch: FC<SwitchProps> = ({
+ className = '',
+ isDisabled = false,
+ items,
+ name,
+ onSwitch,
+ tooltip,
+ value,
+ ...props
+}) => {
+ return (
+ <Fieldset
+ {...props}
+ className={`${styles.fieldset} ${className}`}
+ isDisabled={isDisabled}
+ role="radiogroup"
+ >
+ {tooltip}
+ <div className={styles.switch}>
+ {items.map((item) => (
+ <SwitchItem
+ {...item}
+ isDisabled={isDisabled}
+ isSelected={value === item.value}
+ key={item.id}
+ name={name}
+ onSwitch={onSwitch}
+ />
+ ))}
+ </div>
+ </Fieldset>
+ );
+};