toolbar-items.tsx 6.6 KB

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