switcher.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { FC, createContext, useContext } from 'react'
  2. const SwitcherContext = createContext<
  3. | {
  4. name: string
  5. onChange?: (value: string) => any
  6. defaultValue?: string
  7. disabled: boolean
  8. }
  9. | undefined
  10. >(undefined)
  11. export const Switcher: FC<{
  12. name: string
  13. onChange?: (value: string) => any
  14. defaultValue?: string
  15. disabled?: boolean
  16. }> = ({ name, children, onChange, defaultValue, disabled = false }) => {
  17. return (
  18. <SwitcherContext.Provider
  19. value={{ name, onChange, defaultValue, disabled }}
  20. >
  21. <fieldset>{children}</fieldset>
  22. </SwitcherContext.Provider>
  23. )
  24. }
  25. export const SwitcherItem: FC<{
  26. value: string
  27. label: string
  28. checked?: boolean
  29. }> = ({ value, label, checked = false }) => {
  30. const ctx = useContext(SwitcherContext)
  31. if (!ctx) {
  32. throw new Error('SwitcherItem must be a child of Switcher')
  33. }
  34. const { name, onChange, defaultValue, disabled } = ctx
  35. const id = `${name}-option-${value.replace(/\W/g, '')}`
  36. return (
  37. <>
  38. <input
  39. type="radio"
  40. value={value}
  41. id={id}
  42. className="switcher-input"
  43. name={name}
  44. defaultChecked={!disabled && (checked || defaultValue === value)}
  45. disabled={disabled}
  46. onChange={evt => {
  47. if (onChange) {
  48. onChange(evt.target.value)
  49. }
  50. }}
  51. />
  52. <label htmlFor={id} className="switcher-label" aria-disabled={disabled}>
  53. <span>{label}</span>
  54. </label>
  55. </>
  56. )
  57. }