dropdown-setting.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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-5'
  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. }
  31. export default function DropdownSetting<T extends PossibleValue = string>({
  32. id,
  33. label,
  34. options,
  35. onChange,
  36. value,
  37. optgroup,
  38. description = undefined,
  39. disabled = false,
  40. width = 'default',
  41. loading = false,
  42. }: SettingsMenuSelectProps<T>) {
  43. const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
  44. event => {
  45. const selectedValue = event.target.value
  46. let onChangeValue: PossibleValue = selectedValue
  47. if (typeof value === 'boolean') {
  48. onChangeValue = selectedValue === 'true'
  49. } else if (typeof value === 'number') {
  50. onChangeValue = parseInt(selectedValue, 10)
  51. }
  52. onChange(onChangeValue as T)
  53. },
  54. [onChange, value]
  55. )
  56. return (
  57. <Setting controlId={id} label={label} description={description}>
  58. {loading ? (
  59. <Spinner
  60. animation="border"
  61. aria-hidden="true"
  62. size="sm"
  63. role="status"
  64. />
  65. ) : (
  66. <OLFormSelect
  67. id={id}
  68. className={classNames('ide-dropdown-setting', {
  69. 'ide-dropdown-setting-wide': width === 'wide',
  70. })}
  71. size="sm"
  72. onChange={handleChange}
  73. value={value?.toString()}
  74. disabled={disabled}
  75. >
  76. {options.map(option => (
  77. <option
  78. key={`${id}-${option.value}`}
  79. value={option.value.toString()}
  80. aria-hidden={option.ariaHidden}
  81. disabled={option.disabled}
  82. >
  83. {option.label}
  84. </option>
  85. ))}
  86. {optgroup ? (
  87. <optgroup label={optgroup.label}>
  88. {optgroup.options.map(option => (
  89. <option
  90. value={option.value.toString()}
  91. key={option.value.toString()}
  92. >
  93. {option.label}
  94. </option>
  95. ))}
  96. </optgroup>
  97. ) : null}
  98. </OLFormSelect>
  99. )}
  100. </Setting>
  101. )
  102. }