dropdown-setting.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import OLFormSelect from '@/features/ui/components/ol/ol-form-select'
  2. import { ChangeEventHandler, useCallback } from 'react'
  3. import Setting from './setting'
  4. import classNames from 'classnames'
  5. import { Spinner } from 'react-bootstrap'
  6. type PossibleValue = string | number | boolean
  7. export type Option<T extends PossibleValue = string> = {
  8. value: T
  9. label: string
  10. ariaHidden?: 'true' | 'false'
  11. disabled?: boolean
  12. }
  13. export type Optgroup<T extends PossibleValue = string> = {
  14. label: string
  15. options: Array<Option<T>>
  16. }
  17. type SettingsMenuSelectProps<T extends PossibleValue = string> = {
  18. id: string
  19. label: string
  20. options: Array<Option<T>>
  21. onChange: (val: T) => void
  22. description?: string
  23. // TODO: We can remove optgroup when the spellcheck setting is
  24. // split into 2 and no longer uses it.
  25. optgroup?: Optgroup<T>
  26. value?: T
  27. disabled?: boolean
  28. width?: 'default' | 'wide'
  29. loading?: boolean
  30. translateOptions?: 'yes' | 'no'
  31. }
  32. export default function DropdownSetting<T extends PossibleValue = string>({
  33. id,
  34. label,
  35. options,
  36. onChange,
  37. value,
  38. optgroup,
  39. description = undefined,
  40. disabled = false,
  41. width = 'default',
  42. loading = false,
  43. translateOptions,
  44. }: SettingsMenuSelectProps<T>) {
  45. const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
  46. event => {
  47. const selectedValue = event.target.value
  48. let onChangeValue: PossibleValue = selectedValue
  49. if (typeof value === 'boolean') {
  50. onChangeValue = selectedValue === 'true'
  51. } else if (typeof value === 'number') {
  52. onChangeValue = parseInt(selectedValue, 10)
  53. }
  54. onChange(onChangeValue as T)
  55. },
  56. [onChange, value]
  57. )
  58. return (
  59. <Setting controlId={id} label={label} description={description}>
  60. {loading ? (
  61. <Spinner
  62. animation="border"
  63. aria-hidden="true"
  64. size="sm"
  65. role="status"
  66. />
  67. ) : (
  68. <OLFormSelect
  69. id={id}
  70. className={classNames('ide-dropdown-setting', {
  71. 'ide-dropdown-setting-wide': width === 'wide',
  72. })}
  73. size="sm"
  74. onChange={handleChange}
  75. value={value?.toString()}
  76. disabled={disabled}
  77. translate={translateOptions}
  78. >
  79. {options.map(option => (
  80. <option
  81. key={`${id}-${option.value}`}
  82. value={option.value.toString()}
  83. aria-hidden={option.ariaHidden}
  84. disabled={option.disabled}
  85. >
  86. {option.label}
  87. </option>
  88. ))}
  89. {optgroup ? (
  90. <optgroup label={optgroup.label}>
  91. {optgroup.options.map(option => (
  92. <option
  93. value={option.value.toString()}
  94. key={option.value.toString()}
  95. >
  96. {option.label}
  97. </option>
  98. ))}
  99. </optgroup>
  100. ) : null}
  101. </OLFormSelect>
  102. )}
  103. </Setting>
  104. )
  105. }