editor-switch.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { ChangeEvent, FC, memo, useCallback, useId } from 'react'
  2. import OLTooltip from '@/shared/components/ol/ol-tooltip'
  3. import { sendMB } from '../../../infrastructure/event-tracking'
  4. import { useTranslation } from 'react-i18next'
  5. import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
  6. import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
  7. import { getFileExtension } from '../utils/file'
  8. import { isVisualEditorAvailable } from '../utils/visual-editor'
  9. function EditorSwitch() {
  10. const { t } = useTranslation()
  11. const { showVisual: visual, setShowVisual: setVisual } =
  12. useEditorPropertiesContext()
  13. const { openDocName } = useEditorOpenDocContext()
  14. const inputId = useId()
  15. const richTextAvailable = openDocName
  16. ? isVisualEditorAvailable(openDocName)
  17. : false
  18. const extension = getFileExtension(openDocName || '') ?? ''
  19. const handleChange = useCallback(
  20. (event: ChangeEvent<HTMLInputElement>) => {
  21. const editorType = event.target.value
  22. switch (editorType) {
  23. case 'cm6':
  24. setVisual(false)
  25. break
  26. case 'rich-text':
  27. setVisual(true)
  28. break
  29. }
  30. sendMB('editor-switch-change', { editorType, extension })
  31. },
  32. [extension, setVisual]
  33. )
  34. return (
  35. <div
  36. className="editor-toggle-switch"
  37. aria-label={t('toolbar_code_visual_editor_switch')}
  38. >
  39. <form>
  40. <fieldset className="toggle-switch">
  41. <legend className="visually-hidden">Editor mode.</legend>
  42. <input
  43. type="radio"
  44. name="editor"
  45. value="cm6"
  46. id={inputId}
  47. className="toggle-switch-input"
  48. checked={!richTextAvailable || !visual}
  49. onChange={handleChange}
  50. />
  51. <label htmlFor={inputId} className="toggle-switch-label">
  52. <span>{t('code')}</span>
  53. </label>
  54. <RichTextToggle
  55. checked={richTextAvailable && visual}
  56. disabled={!richTextAvailable}
  57. handleChange={handleChange}
  58. />
  59. </fieldset>
  60. </form>
  61. </div>
  62. )
  63. }
  64. const RichTextToggle: FC<{
  65. checked: boolean
  66. disabled: boolean
  67. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  68. }> = ({ checked, disabled, handleChange }) => {
  69. const { t } = useTranslation()
  70. const inputId = useId()
  71. const toggle = (
  72. <span>
  73. <input
  74. type="radio"
  75. name="editor"
  76. value="rich-text"
  77. id={inputId}
  78. className="toggle-switch-input"
  79. checked={checked}
  80. onChange={handleChange}
  81. disabled={disabled}
  82. />
  83. <label htmlFor={inputId} className="toggle-switch-label">
  84. <span>{t('visual')}</span>
  85. </label>
  86. </span>
  87. )
  88. if (disabled) {
  89. return (
  90. <OLTooltip
  91. description={t('visual_editor_does_not_support_this_file_type')}
  92. id="rich-text-toggle-tooltip"
  93. overlayProps={{ placement: 'bottom' }}
  94. tooltipProps={{ className: 'tooltip-wide' }}
  95. >
  96. {toggle}
  97. </OLTooltip>
  98. )
  99. }
  100. return (
  101. <OLTooltip
  102. id="rich-text-toggle-tooltip"
  103. description={t('toolbar_change_editor_mode')}
  104. overlayProps={{ placement: 'bottom' }}
  105. tooltipProps={{ className: 'tooltip-wide' }}
  106. >
  107. {toggle}
  108. </OLTooltip>
  109. )
  110. }
  111. export default memo(EditorSwitch)