diff --git a/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx b/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx index dbb06aedcd..b17e451f47 100644 --- a/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx +++ b/services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx @@ -1,7 +1,12 @@ import { useCallback, useEffect, useRef, useState } from 'react' import withErrorBoundary from '../../../../infrastructure/error-boundary' import { ErrorBoundaryFallback } from '../../../../shared/components/error-boundary-fallback' -import { EditorState, Extension } from '@codemirror/state' +import { + EditorSelection, + EditorState, + Extension, + StateEffect, +} from '@codemirror/state' import { EditorView, lineNumbers } from '@codemirror/view' import { indentationMarkers } from '@replit/codemirror-indentation-markers' import { highlights, setHighlightsEffect } from '../../extensions/highlights' @@ -100,9 +105,18 @@ function DocumentDiffViewer({ const { before, after } = highlightLocations useEffect(() => { + const effects: StateEffect[] = [setHighlightsEffect.of(highlights)] + if (highlights.length > 0) { + const { from, to } = highlights[0].range + effects.push( + EditorView.scrollIntoView(EditorSelection.range(from, to), { + y: 'center', + }) + ) + } view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: doc }, - effects: setHighlightsEffect.of(highlights), + effects, }) }, [doc, highlights, view]) diff --git a/services/web/frontend/stories/history/document-diff-viewer.stories.tsx b/services/web/frontend/stories/history/document-diff-viewer.stories.tsx index 5c83d8e7bb..33c0dbe8c5 100644 --- a/services/web/frontend/stories/history/document-diff-viewer.stories.tsx +++ b/services/web/frontend/stories/history/document-diff-viewer.stories.tsx @@ -3,23 +3,6 @@ import DocumentDiffViewer from '../../js/features/history/components/diff-view/d import React from 'react' import { Highlight } from '../../js/features/history/services/types/doc' -export default { - title: 'History / Document Diff Viewer', - component: DocumentDiffViewer, - decorators: [ - ScopeDecorator, - (Story: React.ComponentType) => ( -
- -
- ), - ], -} - -export const Highlights = () => { - return -} - const highlights: Highlight[] = [ { type: 'addition', @@ -47,7 +30,7 @@ const highlights: Highlight[] = [ }, ] -const content = `\\documentclass{article} +const doc = `\\documentclass{article} % Language setting % Replace \`english' with e.g. \`spanish' to change the document language @@ -131,3 +114,38 @@ Once you're familiar with the editor, you can find various project settings in t \\bibliography{sample} \\end{document}` + +export default { + title: 'History / Document Diff Viewer', + component: DocumentDiffViewer, + args: { doc, highlights }, + argTypes: { + doc: { + table: { disable: true }, + }, + highlights: { + table: { disable: true }, + }, + }, + decorators: [ + ScopeDecorator, + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} + +export const Highlights = ( + args: React.ComponentProps +) => { + return +} + +export const ScrollToFirstHighlight = ( + args: React.ComponentProps +) => { + const lastHighlightOnly = args.highlights.slice(-1) + return +} diff --git a/services/web/test/frontend/features/history/components/document-diff-viewer.spec.tsx b/services/web/test/frontend/features/history/components/document-diff-viewer.spec.tsx index e43fd8f600..553e785315 100644 --- a/services/web/test/frontend/features/history/components/document-diff-viewer.spec.tsx +++ b/services/web/test/frontend/features/history/components/document-diff-viewer.spec.tsx @@ -144,4 +144,37 @@ describe('document diff viewer', function () { cy.get('.previous-highlight-button').should('have.length', 1) cy.get('.next-highlight-button').should('have.length', 1) }) + + it('scrolls to first change', function () { + const scope = mockScope() + const finalHighlightOnly = highlights.slice(-1) + + cy.mount( + + + + + + ) + + cy.get('.cm-scroller').first().invoke('scrollTop').should('not.equal', 0) + cy.get('.ol-addition-marker') + .first() + .then($marker => { + cy.get('.cm-content') + .first() + .then($content => { + const contentRect = $content[0].getBoundingClientRect() + const markerRect = $marker[0].getBoundingClientRect() + expect(markerRect.top).to.be.within( + contentRect.top, + contentRect.bottom + ) + expect(markerRect.bottom).to.be.within( + contentRect.top, + contentRect.bottom + ) + }) + }) + }) })