toolbar-items.tsx 6.7 KB

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