settings-menu-select.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { ChangeEventHandler, useCallback } from 'react'
  2. type PossibleValue = string | number | 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. const selectedValue = event.target.value
  34. let onChangeValue: PossibleValue = selectedValue
  35. if (typeof value === 'boolean') {
  36. onChangeValue = selectedValue === 'true'
  37. } else if (typeof value === 'number') {
  38. onChangeValue = parseInt(selectedValue, 10)
  39. }
  40. onChange(onChangeValue as T)
  41. },
  42. [onChange, value]
  43. )
  44. return (
  45. <div className="form-group left-menu-setting">
  46. <label htmlFor={`settings-menu-${name}`}>{label}</label>
  47. {loading ? (
  48. <p className="loading pull-right">
  49. <i className="fa fa-fw fa-spin fa-refresh" />
  50. </p>
  51. ) : (
  52. <select
  53. id={`settings-menu-${name}`}
  54. className="form-control"
  55. onChange={handleChange}
  56. value={value?.toString()}
  57. >
  58. {options.map(option => (
  59. <option
  60. key={`${name}-${option.value}`}
  61. value={option.value.toString()}
  62. aria-hidden={option.ariaHidden}
  63. disabled={option.disabled}
  64. >
  65. {option.label}
  66. </option>
  67. ))}
  68. {optgroup ? (
  69. <optgroup label={optgroup.label}>
  70. {optgroup.options.map(option => (
  71. <option
  72. value={option.value.toString()}
  73. key={option.value.toString()}
  74. >
  75. {option.label}
  76. </option>
  77. ))}
  78. </optgroup>
  79. ) : null}
  80. </select>
  81. )}
  82. </div>
  83. )
  84. }