editor-switch.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { ChangeEvent, FC, memo, useCallback } from 'react'
  2. import useScopeValue from '../../../shared/hooks/use-scope-value'
  3. import Tooltip from '../../../shared/components/tooltip'
  4. import { sendMB } from '../../../infrastructure/event-tracking'
  5. import isValidTeXFile from '../../../main/is-valid-tex-file'
  6. import { useTranslation } from 'react-i18next'
  7. import SplitTestBadge from '../../../shared/components/split-test-badge'
  8. function EditorSwitch() {
  9. const { t } = useTranslation()
  10. const [newSourceEditor, setNewSourceEditor] = useScopeValue(
  11. 'editor.newSourceEditor'
  12. )
  13. const [visual, setVisual] = useScopeValue('editor.showVisual')
  14. const [docName] = useScopeValue('editor.open_doc_name')
  15. const richTextAvailable = isValidTeXFile(docName)
  16. // TODO: rename this after legacy & toolbar split tests are complete
  17. const richTextOrVisual = richTextAvailable && visual
  18. const handleChange = useCallback(
  19. event => {
  20. const editorType = event.target.value
  21. switch (editorType) {
  22. case 'ace':
  23. setVisual(false)
  24. setNewSourceEditor(false)
  25. break
  26. case 'cm6':
  27. setVisual(false)
  28. setNewSourceEditor(true)
  29. break
  30. case 'rich-text':
  31. setVisual(true)
  32. setNewSourceEditor(true)
  33. break
  34. }
  35. sendMB('editor-switch-change', { editorType })
  36. },
  37. [setVisual, setNewSourceEditor]
  38. )
  39. return (
  40. <div className="editor-toggle-switch">
  41. <fieldset className="toggle-switch">
  42. <legend className="sr-only">Editor mode.</legend>
  43. <input
  44. type="radio"
  45. name="editor"
  46. value="cm6"
  47. id="editor-switch-cm6"
  48. className="toggle-switch-input"
  49. checked={!richTextOrVisual && !!newSourceEditor}
  50. onChange={handleChange}
  51. />
  52. <label htmlFor="editor-switch-cm6" className="toggle-switch-label">
  53. <span>{t('code_editor')}</span>
  54. </label>
  55. <RichTextToggle
  56. checked={!!richTextOrVisual}
  57. disabled={!richTextAvailable}
  58. handleChange={handleChange}
  59. />
  60. </fieldset>
  61. {!!richTextOrVisual && (
  62. <SplitTestBadge splitTestName="rich-text" displayOnVariants={['cm6']} />
  63. )}
  64. </div>
  65. )
  66. }
  67. const RichTextToggle: FC<{
  68. checked: boolean
  69. disabled: boolean
  70. handleChange: (event: ChangeEvent<HTMLInputElement>) => void
  71. }> = ({ checked, disabled, handleChange }) => {
  72. const { t } = useTranslation()
  73. const toggle = (
  74. <span>
  75. <input
  76. type="radio"
  77. name="editor"
  78. value="rich-text"
  79. id="editor-switch-rich-text"
  80. className="toggle-switch-input"
  81. checked={checked}
  82. onChange={handleChange}
  83. disabled={disabled}
  84. />
  85. <label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
  86. <span>{t('visual_editor')}</span>
  87. </label>
  88. </span>
  89. )
  90. if (disabled) {
  91. return (
  92. <Tooltip
  93. description={t('the_visual_editor_is_only_available_for_tex_files')}
  94. id="rich-text-toggle-tooltip"
  95. overlayProps={{ placement: 'bottom' }}
  96. tooltipProps={{ className: 'tooltip-wide' }}
  97. >
  98. {toggle}
  99. </Tooltip>
  100. )
  101. }
  102. return toggle
  103. }
  104. export default memo(EditorSwitch)