settings-menu-select.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import OLFormGroup from '@/shared/components/ol/ol-form-group'
  2. import OLFormLabel from '@/shared/components/ol/ol-form-label'
  3. import OLFormSelect from '@/shared/components/ol/ol-form-select'
  4. import { ChangeEventHandler, useCallback, useEffect, useRef } from 'react'
  5. import { useEditorLeftMenuContext } from '@/features/editor-left-menu/components/editor-left-menu-context'
  6. import OLSpinner from '@/shared/components/ol/ol-spinner'
  7. type PossibleValue = string | number | boolean
  8. export type Option<T extends PossibleValue = string> = {
  9. value: T
  10. label: string
  11. ariaHidden?: 'true' | 'false'
  12. disabled?: boolean
  13. }
  14. export type Optgroup<T extends PossibleValue = string> = {
  15. label: string
  16. options: Array<Option<T>>
  17. }
  18. type SettingsMenuSelectProps<T extends PossibleValue = string> = {
  19. label: string
  20. name: string
  21. options?: Array<Option<T>>
  22. optgroups?: Array<Optgroup<T>>
  23. loading?: boolean
  24. onChange: (val: T) => void
  25. value?: T
  26. disabled?: boolean
  27. translateOptions?: 'yes' | 'no'
  28. }
  29. export default function SettingsMenuSelect<T extends PossibleValue = string>({
  30. label,
  31. name,
  32. options,
  33. optgroups,
  34. loading,
  35. onChange,
  36. value,
  37. disabled = false,
  38. translateOptions,
  39. }: SettingsMenuSelectProps<T>) {
  40. const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
  41. event => {
  42. const selectedValue = event.target.value
  43. let onChangeValue: PossibleValue = selectedValue
  44. if (typeof value === 'boolean') {
  45. onChangeValue = selectedValue === 'true'
  46. } else if (typeof value === 'number') {
  47. onChangeValue = parseInt(selectedValue, 10)
  48. }
  49. onChange(onChangeValue as T)
  50. },
  51. [onChange, value]
  52. )
  53. const { settingToFocus } = useEditorLeftMenuContext()
  54. const selectRef = useRef<HTMLSelectElement | null>(null)
  55. useEffect(() => {
  56. if (settingToFocus === name && selectRef.current) {
  57. selectRef.current.scrollIntoView({
  58. block: 'center',
  59. behavior: 'smooth',
  60. })
  61. selectRef.current.focus()
  62. }
  63. // clear the focus setting
  64. window.dispatchEvent(
  65. new CustomEvent('ui.focus-setting', { detail: undefined })
  66. )
  67. }, [name, settingToFocus])
  68. return (
  69. <OLFormGroup
  70. controlId={`settings-menu-${name}`}
  71. className="left-menu-setting"
  72. >
  73. <OLFormLabel>{label}</OLFormLabel>
  74. {loading ? (
  75. <OLSpinner size="sm" />
  76. ) : (
  77. <OLFormSelect
  78. size="sm"
  79. onChange={handleChange}
  80. value={value?.toString()}
  81. disabled={disabled}
  82. ref={selectRef}
  83. translate={translateOptions}
  84. >
  85. {options?.map(option => (
  86. <option
  87. key={`${name}-${option.value}`}
  88. value={option.value.toString()}
  89. aria-hidden={option.ariaHidden}
  90. disabled={option.disabled}
  91. >
  92. {option.label}
  93. </option>
  94. ))}
  95. {optgroups?.map(optgroup => (
  96. <optgroup label={optgroup.label} key={optgroup.label}>
  97. {optgroup.options.map(option => (
  98. <option
  99. value={option.value.toString()}
  100. key={option.value.toString()}
  101. >
  102. {option.label}
  103. </option>
  104. ))}
  105. </optgroup>
  106. ))}
  107. </OLFormSelect>
  108. )}
  109. </OLFormGroup>
  110. )
  111. }