overleaf/services/web/frontend/js/features/source-editor/extensions/index.ts
David a323f3af75 Implement a floating "Add comment" button for the redesigned review panel (#19891)
* Implement floating Add comment button

* Fix comment typo

* Remove unused imports

* Make tooltip always appear above cursor

Co-authored-by: Domagoj Kriskovic <dom.kriskovic@overleaf.com>

* Refactor how new comment form is positioned

* Add missing file

* Create new map when rendering positions

* Use codemirror state to manage ranges and allow for mutliple in-progress comments

* Memoise sorting

* Create new ranges map each time it is changed

* Add back mutation observer

* Only allow single tooltip

* Fix typo

* Convert state field to store a single tooltip

* Make add comment tooltip content a react component

* Refactor to remove usages of !important

* Use RangeSet to keep track of new comment ranges

* Fix logic broken in rebase

* Map ranges through document changes

* Add decorations for in-progress comments

* Use set-review-panel-open rather than an editor event to open review panel

* Implement new designs for add comment form

* Add padding to textarea

* Fix bug where comment was being submitted for incorrect range

* Add missing key to ReviewPanelAddComment

* Store new comment ranges as a DecorationSet

* Small refactor to how ReviewPanelAddCommens are rendered

* Make op prop to ReviewPanelEntry required

* Add handling for disabling of add comemnt form buttons

* Move viewer check inside AddCommentTooltip

* Ensure that add comment button doesn't reshow when collaborators edit the document

* Remove unneeded op check in ReviewPanelEntry

* Update services/web/frontend/js/features/review-panel-new/components/review-panel-add-comment.tsx

Co-authored-by: Domagoj Kriskovic <dom.kriskovic@overleaf.com>

---------

Co-authored-by: Domagoj Kriskovic <dom.kriskovic@overleaf.com>
GitOrigin-RevId: 3110845f6a557310f3bf72014689e2f2ab53e966
2024-09-17 08:04:58 +00:00

153 lines
6.2 KiB
TypeScript

import {
EditorView,
rectangularSelection,
tooltips,
crosshairCursor,
dropCursor,
highlightActiveLineGutter,
} from '@codemirror/view'
import { EditorState, Extension } from '@codemirror/state'
import { foldGutter, indentOnInput, indentUnit } from '@codemirror/language'
import { history } from '@codemirror/commands'
import { language } from './language'
import { lineWrappingIndentation } from './line-wrapping-indentation'
import { theme } from './theme'
import { realtime } from './realtime'
import { cursorPosition } from './cursor-position'
import { scrollPosition } from './scroll-position'
import { annotations } from './annotations'
import { cursorHighlights } from './cursor-highlights'
import { autoComplete } from './auto-complete'
import { editable } from './editable'
import { autoPair } from './auto-pair'
import { phrases } from './phrases'
import { spelling } from './spelling'
import { symbolPalette } from './symbol-palette'
import { trackChanges } from './track-changes'
import { search } from './search'
import { filterCharacters } from './filter-characters'
import { keybindings } from './keybindings'
import { bracketMatching, bracketSelection } from './bracket-matching'
import { verticalOverflow } from './vertical-overflow'
import { thirdPartyExtensions } from './third-party-extensions'
import { lineNumbers } from './line-numbers'
import { highlightActiveLine } from './highlight-active-line'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import { emptyLineFiller } from './empty-line-filler'
import { goToLinePanel } from './go-to-line'
import { drawSelection } from './draw-selection'
import { visual } from './visual/visual'
import { inlineBackground } from './inline-background'
import { indentationMarkers } from './indentation-markers'
import { codemirrorDevTools } from '../languages/latex/codemirror-dev-tools'
import { keymaps } from './keymaps'
import { shortcuts } from './shortcuts'
import { effectListeners } from './effect-listeners'
import { highlightSpecialChars } from './highlight-special-chars'
import { toolbarPanel } from './toolbar/toolbar-panel'
import { geometryChangeEvent } from './geometry-change-event'
import { docName } from './doc-name'
import { fileTreeItemDrop } from './file-tree-item-drop'
import { mathPreview } from './math-preview'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { ranges } from './ranges'
import { trackDetachedComments } from './track-detached-comments'
import { addComment } from './add-comment'
const moduleExtensions: Array<() => Extension> = importOverleafModules(
'sourceEditorExtensions'
).map((item: { import: { extension: Extension } }) => item.import.extension)
export const createExtensions = (options: Record<string, any>): Extension[] => [
lineNumbers(),
highlightSpecialChars(options.visual.visual),
// The built-in extension that manages the history stack,
// configured to increase the maximum delay between adjacent grouped edits
history({ newGroupDelay: 250 }),
// The built-in extension that displays buttons for folding code in a gutter element,
// configured with custom openText and closeText symbols.
foldGutter({
openText: '▾',
closedText: '▸',
}),
drawSelection(),
// A built-in facet that is set to true to allow multiple selections.
// This makes the editor more like a code editor than Google Docs or Microsoft Word,
// which only have single selections.
EditorState.allowMultipleSelections.of(true),
// A built-in extension that enables soft line wrapping.
EditorView.lineWrapping,
// A built-in extension that re-indents input if the language defines an indentOnInput field in its language data.
indentOnInput(),
lineWrappingIndentation(options.visual.visual),
indentationMarkers(options.visual.visual),
bracketMatching(),
bracketSelection(),
// A built-in extension that enables rectangular selections, created by dragging a new selection while holding down Alt.
rectangularSelection(),
// A built-in extension that turns the pointer into a crosshair while Alt is pressed.
crosshairCursor(),
// A built-in extension that shows where dragged content will be dropped.
dropCursor(),
// A built-in extension that is used for configuring tooltip behaviour,
// configured so that the tooltip parent is the document body,
// to avoid cutting off tooltips which overflow the editor.
tooltips({
parent: document.body,
}),
keymaps,
goToLinePanel(),
filterCharacters(),
// NOTE: `autoComplete` needs to be before `keybindings` so that arrow key handling
// in the autocomplete pop-up takes precedence over Vim/Emacs key bindings
autoComplete(options.settings),
// NOTE: `keybindings` needs to be before `language` so that Vim/Emacs bindings take
// precedence over language-specific keyboard shortcuts
keybindings(),
docName(options.docName),
// NOTE: `annotations` needs to be before `language`
annotations(),
language(options.docName, options.metadata, options.settings),
indentUnit.of(' '), // 4 spaces
theme(options.theme),
realtime(options.currentDoc, options.handleError),
cursorPosition(options.currentDoc),
scrollPosition(options.currentDoc, options.visual),
cursorHighlights(),
autoPair(options.settings),
editable(),
search(),
phrases(options.phrases),
spelling(options.spelling),
shortcuts,
symbolPalette(),
// NOTE: `emptyLineFiller` needs to be before `trackChanges`,
// so the decorations are added in the correct order.
emptyLineFiller(),
isSplitTestEnabled('review-panel-redesign')
? ranges(options.currentDoc)
: trackChanges(options.currentDoc, options.changeManager),
trackDetachedComments(options.currentDoc),
visual(options.visual),
mathPreview(options.settings.mathPreview),
addComment(),
toolbarPanel(),
verticalOverflow(),
highlightActiveLine(options.visual.visual),
// The built-in extension that highlights the active line in the gutter.
highlightActiveLineGutter(),
inlineBackground(options.visual.visual),
codemirrorDevTools(),
// Send exceptions to Sentry
EditorView.exceptionSink.of(options.handleException),
// CodeMirror extensions provided by modules
moduleExtensions.map(extension => extension()),
thirdPartyExtensions(),
effectListeners(),
geometryChangeEvent(),
fileTreeItemDrop(),
]