toolbar-items.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import { FC, memo, useCallback } from 'react'
  2. import { EditorSelection, EditorState } from '@codemirror/state'
  3. import { EditorView } from '@codemirror/view'
  4. import { useEditorContext } from '../../../../shared/context/editor-context'
  5. import useScopeEventEmitter from '../../../../shared/hooks/use-scope-event-emitter'
  6. import { useLayoutContext } from '../../../../shared/context/layout-context'
  7. import { withinFormattingCommand } from '../../utils/tree-operations/ancestors'
  8. import { ToolbarButton } from './toolbar-button'
  9. import { redo, undo } from '@codemirror/commands'
  10. import * as commands from '../../extensions/toolbar/commands'
  11. import { SectionHeadingDropdown } from './section-heading-dropdown'
  12. import { canAddComment } from '../../extensions/toolbar/comments'
  13. import getMeta from '../../../../utils/meta'
  14. import { InsertFigureDropdown } from './insert-figure-dropdown'
  15. import { useTranslation } from 'react-i18next'
  16. import { MathDropdown } from './math-dropdown'
  17. import { TableInserterDropdown } from './table-inserter-dropdown'
  18. const isMac = /Mac/.test(window.navigator?.platform)
  19. export const ToolbarItems: FC<{
  20. state: EditorState
  21. overflowed?: Set<string>
  22. languageName?: string
  23. visual: boolean
  24. listDepth: number
  25. }> = memo(function ToolbarItems({
  26. state,
  27. overflowed,
  28. languageName,
  29. visual,
  30. listDepth,
  31. }) {
  32. const { t } = useTranslation()
  33. const { toggleSymbolPalette, showSymbolPalette } = useEditorContext()
  34. const isActive = withinFormattingCommand(state)
  35. const addCommentEmitter = useScopeEventEmitter('comment:start_adding')
  36. const { setReviewPanelOpen } = useLayoutContext()
  37. const splitTestVariants = getMeta('ol-splitTestVariants', {})
  38. const addComment = useCallback(
  39. (view: EditorView) => {
  40. const range = view.state.selection.main
  41. if (range.empty) {
  42. const line = view.state.doc.lineAt(range.head)
  43. view.dispatch({
  44. selection: EditorSelection.range(line.from, line.to),
  45. })
  46. }
  47. setReviewPanelOpen(true)
  48. addCommentEmitter()
  49. },
  50. [addCommentEmitter, setReviewPanelOpen]
  51. )
  52. const showFigureModal = splitTestVariants['figure-modal'] === 'enabled'
  53. const showTableGenerator = splitTestVariants['table-generator'] === 'enabled'
  54. const symbolPaletteAvailable = getMeta('ol-symbolPaletteAvailable')
  55. const showGroup = (group: string) => !overflowed || overflowed.has(group)
  56. return (
  57. <>
  58. {showGroup('group-history') && (
  59. <div className="ol-cm-toolbar-button-group">
  60. <ToolbarButton
  61. id="toolbar-undo"
  62. label={t('toolbar_undo')}
  63. command={undo}
  64. icon="undo"
  65. shortcut={isMac ? '⌘Z' : 'Ctrl+Z'}
  66. />
  67. <ToolbarButton
  68. id="toolbar-redo"
  69. label={t('toolbar_redo')}
  70. command={redo}
  71. icon="repeat"
  72. shortcut={isMac ? '⇧⌘Z' : 'Ctrl+Y'}
  73. />
  74. </div>
  75. )}
  76. {languageName === 'latex' && (
  77. <>
  78. {showGroup('group-section') && (
  79. <div
  80. className="ol-cm-toolbar-button-group"
  81. data-overflow="group-section"
  82. >
  83. <SectionHeadingDropdown />
  84. </div>
  85. )}
  86. {showGroup('group-format') && (
  87. <div className="ol-cm-toolbar-button-group">
  88. <ToolbarButton
  89. id="toolbar-format-bold"
  90. label={t('toolbar_format_bold')}
  91. command={commands.toggleBold}
  92. active={isActive('\\textbf')}
  93. icon="bold"
  94. shortcut={isMac ? '⌘B' : 'Ctrl+B'}
  95. />
  96. <ToolbarButton
  97. id="toolbar-format-italic"
  98. label={t('toolbar_format_italic')}
  99. command={commands.toggleItalic}
  100. active={isActive('\\textit')}
  101. icon="italic"
  102. shortcut={isMac ? '⌘I' : 'Ctrl+I'}
  103. />
  104. </div>
  105. )}
  106. {showGroup('group-math') && (
  107. <div
  108. className="ol-cm-toolbar-button-group"
  109. data-overflow="group-math"
  110. >
  111. <MathDropdown />
  112. {symbolPaletteAvailable && (
  113. <ToolbarButton
  114. id="toolbar-toggle-symbol-palette"
  115. label={t('toolbar_toggle_symbol_palette')}
  116. active={showSymbolPalette}
  117. command={toggleSymbolPalette}
  118. icon="Ω"
  119. textIcon
  120. className="ol-cm-toolbar-button-math"
  121. />
  122. )}
  123. </div>
  124. )}
  125. {showGroup('group-misc') && (
  126. <div
  127. className="ol-cm-toolbar-button-group"
  128. data-overflow="group-misc"
  129. >
  130. <ToolbarButton
  131. id="toolbar-href"
  132. label={t('toolbar_insert_link')}
  133. command={commands.wrapInHref}
  134. icon="link"
  135. />
  136. <ToolbarButton
  137. id="toolbar-ref"
  138. label={t('toolbar_insert_cross_reference')}
  139. command={commands.insertRef}
  140. icon="tag"
  141. />
  142. <ToolbarButton
  143. id="toolbar-cite"
  144. label={t('toolbar_insert_citation')}
  145. command={commands.insertCite}
  146. icon="book"
  147. />
  148. <ToolbarButton
  149. id="toolbar-add-comment"
  150. label={t('toolbar_add_comment')}
  151. command={addComment}
  152. disabled={!canAddComment(state)}
  153. icon="comment"
  154. hidden // enable this if an alternative to the floating "Add Comment" button is needed
  155. />
  156. {showFigureModal ? (
  157. <InsertFigureDropdown />
  158. ) : (
  159. <ToolbarButton
  160. id="toolbar-figure"
  161. label={t('toolbar_insert_figure')}
  162. command={commands.insertFigure}
  163. icon="picture-o"
  164. />
  165. )}
  166. {showTableGenerator && <TableInserterDropdown />}
  167. </div>
  168. )}
  169. {showGroup('group-list') && (
  170. <div
  171. className="ol-cm-toolbar-button-group"
  172. data-overflow="group-list"
  173. >
  174. <ToolbarButton
  175. id="toolbar-bullet-list"
  176. label={t('toolbar_bullet_list')}
  177. command={commands.toggleBulletList}
  178. icon="list-ul"
  179. />
  180. <ToolbarButton
  181. id="toolbar-numbered-list"
  182. label={t('toolbar_numbered_list')}
  183. command={commands.toggleNumberedList}
  184. icon="list-ol"
  185. />
  186. <ToolbarButton
  187. id="toolbar-format-indent-decrease"
  188. label={t('toolbar_decrease_indent')}
  189. command={commands.indentDecrease}
  190. icon="outdent"
  191. shortcut={visual ? (isMac ? '⌘[' : 'Ctrl+[') : undefined}
  192. disabled={listDepth < 2}
  193. />
  194. <ToolbarButton
  195. id="toolbar-format-indent-increase"
  196. label={t('toolbar_increase_indent')}
  197. command={commands.indentIncrease}
  198. icon="indent"
  199. shortcut={visual ? (isMac ? '⌘]' : 'Ctrl+]') : undefined}
  200. disabled={listDepth < 1}
  201. />
  202. </div>
  203. )}
  204. </>
  205. )}
  206. </>
  207. )
  208. })