settings-menu-select.tsx 2.4 KB

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