settings-menu-select.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import { ChangeEventHandler, useCallback } from 'react'
  2. type PossibleValue = string | boolean
  3. export type Option<T extends PossibleValue = string> = {
  4. value: T
  5. label: string
  6. ariaHidden?: 'true' | 'false'
  7. disabled?: boolean
  8. }
  9. export type Optgroup<T extends PossibleValue = string> = {
  10. label: string
  11. options: Array<Option<T>>
  12. }
  13. type SettingsMenuSelectProps<T extends PossibleValue = string> = {
  14. label: string
  15. name: string
  16. options: Array<Option<T>>
  17. optgroup?: Optgroup<T>
  18. loading?: boolean
  19. onChange: (val: T) => void
  20. value?: T
  21. }
  22. export default function SettingsMenuSelect<T extends PossibleValue = string>({
  23. label,
  24. name,
  25. options,
  26. optgroup,
  27. loading,
  28. onChange,
  29. value,
  30. }: SettingsMenuSelectProps<T>) {
  31. const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
  32. event => {
  33. let value: PossibleValue = event.target.value
  34. if (value === 'true' || value === 'false') {
  35. value = value === 'true'
  36. }
  37. onChange(value as T)
  38. },
  39. [onChange]
  40. )
  41. return (
  42. <div className="form-group left-menu-setting">
  43. <label htmlFor={`settings-menu-${name}`}>{label}</label>
  44. {loading ? (
  45. <p className="loading pull-right">
  46. <i className="fa fa-fw fa-spin fa-refresh" />
  47. </p>
  48. ) : (
  49. <select
  50. id={`settings-menu-${name}`}
  51. className="form-control"
  52. onChange={handleChange}
  53. value={value?.toString()}
  54. >
  55. {options.map(option => (
  56. <option
  57. key={`${name}-${option.value}`}
  58. value={option.value.toString()}
  59. aria-hidden={option.ariaHidden}
  60. disabled={option.disabled}
  61. >
  62. {option.label}
  63. </option>
  64. ))}
  65. {optgroup ? (
  66. <optgroup label={optgroup.label}>
  67. {optgroup.options.map(option => (
  68. <option
  69. value={option.value.toString()}
  70. key={option.value.toString()}
  71. >
  72. {option.label}
  73. </option>
  74. ))}
  75. </optgroup>
  76. ) : null}
  77. </select>
  78. )}
  79. </div>
  80. )
  81. }