mirror of
https://github.com/overleaf/overleaf.git
synced 2025-01-27 09:42:00 +00:00
Merge pull request #12668 from overleaf/td-history-scroll-to-first-change
Scroll to first change in history document diff viewer GitOrigin-RevId: e135877ca440c5eb2732890e8723d9098444727f
This commit is contained in:
parent
99e1ff0804
commit
5f5e07a334
3 changed files with 85 additions and 20 deletions
|
@ -1,7 +1,12 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import withErrorBoundary from '../../../../infrastructure/error-boundary'
|
import withErrorBoundary from '../../../../infrastructure/error-boundary'
|
||||||
import { ErrorBoundaryFallback } from '../../../../shared/components/error-boundary-fallback'
|
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 { EditorView, lineNumbers } from '@codemirror/view'
|
||||||
import { indentationMarkers } from '@replit/codemirror-indentation-markers'
|
import { indentationMarkers } from '@replit/codemirror-indentation-markers'
|
||||||
import { highlights, setHighlightsEffect } from '../../extensions/highlights'
|
import { highlights, setHighlightsEffect } from '../../extensions/highlights'
|
||||||
|
@ -100,9 +105,18 @@ function DocumentDiffViewer({
|
||||||
const { before, after } = highlightLocations
|
const { before, after } = highlightLocations
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const effects: StateEffect<unknown>[] = [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({
|
view.dispatch({
|
||||||
changes: { from: 0, to: view.state.doc.length, insert: doc },
|
changes: { from: 0, to: view.state.doc.length, insert: doc },
|
||||||
effects: setHighlightsEffect.of(highlights),
|
effects,
|
||||||
})
|
})
|
||||||
}, [doc, highlights, view])
|
}, [doc, highlights, view])
|
||||||
|
|
||||||
|
|
|
@ -3,23 +3,6 @@ import DocumentDiffViewer from '../../js/features/history/components/diff-view/d
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Highlight } from '../../js/features/history/services/types/doc'
|
import { Highlight } from '../../js/features/history/services/types/doc'
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'History / Document Diff Viewer',
|
|
||||||
component: DocumentDiffViewer,
|
|
||||||
decorators: [
|
|
||||||
ScopeDecorator,
|
|
||||||
(Story: React.ComponentType) => (
|
|
||||||
<div style={{ height: '90vh' }}>
|
|
||||||
<Story />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Highlights = () => {
|
|
||||||
return <DocumentDiffViewer doc={content} highlights={highlights} />
|
|
||||||
}
|
|
||||||
|
|
||||||
const highlights: Highlight[] = [
|
const highlights: Highlight[] = [
|
||||||
{
|
{
|
||||||
type: 'addition',
|
type: 'addition',
|
||||||
|
@ -47,7 +30,7 @@ const highlights: Highlight[] = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const content = `\\documentclass{article}
|
const doc = `\\documentclass{article}
|
||||||
|
|
||||||
% Language setting
|
% Language setting
|
||||||
% Replace \`english' with e.g. \`spanish' to change the document language
|
% 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}
|
\\bibliography{sample}
|
||||||
|
|
||||||
\\end{document}`
|
\\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) => (
|
||||||
|
<div style={{ height: '90vh' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Highlights = (
|
||||||
|
args: React.ComponentProps<typeof DocumentDiffViewer>
|
||||||
|
) => {
|
||||||
|
return <DocumentDiffViewer {...args} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ScrollToFirstHighlight = (
|
||||||
|
args: React.ComponentProps<typeof DocumentDiffViewer>
|
||||||
|
) => {
|
||||||
|
const lastHighlightOnly = args.highlights.slice(-1)
|
||||||
|
return <DocumentDiffViewer {...args} highlights={lastHighlightOnly} />
|
||||||
|
}
|
||||||
|
|
|
@ -144,4 +144,37 @@ describe('document diff viewer', function () {
|
||||||
cy.get('.previous-highlight-button').should('have.length', 1)
|
cy.get('.previous-highlight-button').should('have.length', 1)
|
||||||
cy.get('.next-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(
|
||||||
|
<Container>
|
||||||
|
<EditorProviders scope={scope}>
|
||||||
|
<DocumentDiffViewer doc={doc} highlights={finalHighlightOnly} />
|
||||||
|
</EditorProviders>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue