11import { Text , EditorState , ChangeSet , ChangeDesc , RangeSet , EditorSelection } from "@codemirror/state"
2- import { Rect , isScrolledToBottom , getScale } from "./dom"
2+ import { Rect , isScrolledToBottom , getScale , scrollableParents } from "./dom"
33import { HeightMap , HeightOracle , BlockInfo , MeasuredHeights , QueryType , heightRelevantDecoChanges ,
44 clearHeightChangeFlag , heightChangeFlag } from "./heightmap"
55import { decorations , outerDecorations , ViewUpdate , UpdateFlag , ChangedRange , ScrollTarget , nativeSelectionHidden ,
@@ -120,12 +120,17 @@ export class ViewState {
120120 contentDOMHeight = 0 // contentDOM.getBoundingClientRect().height
121121 editorHeight = 0 // scrollDOM.clientHeight, unscaled
122122 editorWidth = 0 // scrollDOM.clientWidth, unscaled
123- scrollTop = 0 // Last seen scrollDOM.scrollTop, scaled
124- scrolledToBottom = false
125123 // The CSS-transformation scale of the editor (transformed size /
126124 // concrete size)
127125 scaleX = 1
128126 scaleY = 1
127+
128+ // The nearest vertically-scrollable parent. null means window is nearest
129+ scrollParent : HTMLElement | null
130+ // Last seen vertical offset of the element at the top of the scroll
131+ // container, or top of the window if there's no wrapping scroller
132+ scrollOffset = 0
133+ scrolledToBottom = false
129134 // The vertical position (document-relative) to which to anchor the
130135 // scroll position. -1 means anchor to the end of the document.
131136 scrollAnchorPos = 0
@@ -169,7 +174,7 @@ export class ViewState {
169174 // the right place.
170175 mustEnforceCursorAssoc = false
171176
172- constructor ( public state : EditorState ) {
177+ constructor ( public view : EditorView , public state : EditorState ) {
173178 let guessWrapping = state . facet ( contentAttributes ) . some ( v => typeof v != "function" && v . class == "cm-lineWrapping" )
174179 this . heightOracle = new HeightOracle ( guessWrapping )
175180 this . stateDeco = staticDeco ( state )
@@ -182,6 +187,7 @@ export class ViewState {
182187 this . updateViewportLines ( )
183188 this . lineGaps = this . ensureLineGaps ( [ ] )
184189 this . lineGapDeco = Decoration . set ( this . lineGaps . map ( gap => gap . draw ( this , false ) ) )
190+ this . scrollParent = view . scrollDOM
185191 this . computeVisibleRanges ( )
186192 }
187193
@@ -222,7 +228,7 @@ export class ViewState {
222228 let heightChanges = ChangedRange . extendWithRanges ( contentChanges , heightRelevantDecoChanges (
223229 prevDeco , this . stateDeco , update ? update . changes : ChangeSet . empty ( this . state . doc . length ) ) )
224230 let prevHeight = this . heightMap . height
225- let scrollAnchor = this . scrolledToBottom ? null : this . scrollAnchorAt ( this . scrollTop )
231+ let scrollAnchor = this . scrolledToBottom ? null : this . scrollAnchorAt ( this . scrollOffset )
226232 clearHeightChangeFlag ( )
227233 this . heightMap = this . heightMap . applyChanges ( this . stateDeco , update . startState . doc ,
228234 this . heightOracle . setDoc ( this . state . doc ) , heightChanges )
@@ -258,8 +264,8 @@ export class ViewState {
258264 this . mustEnforceCursorAssoc = true
259265 }
260266
261- measure ( view : EditorView ) {
262- let dom = view . contentDOM , style = window . getComputedStyle ( dom )
267+ measure ( ) {
268+ let { view } = this , dom = view . contentDOM , style = window . getComputedStyle ( dom )
263269 let oracle = this . heightOracle
264270 let whiteSpace = style . whiteSpace !
265271 this . defaultTextDirection = style . direction == "rtl" ? Direction . RTL : Direction . LTR
@@ -294,12 +300,18 @@ export class ViewState {
294300 this . editorWidth = view . scrollDOM . clientWidth
295301 result |= UpdateFlag . Geometry
296302 }
297- let scrollTop = view . scrollDOM . scrollTop * this . scaleY
298- if ( this . scrollTop != scrollTop ) {
303+ let scrollParent = scrollableParents ( this . view . contentDOM , false ) . y
304+ if ( scrollParent != this . scrollParent ) {
305+ this . scrollParent = scrollParent
299306 this . scrollAnchorHeight = - 1
300- this . scrollTop = scrollTop
307+ this . scrollOffset = 0
301308 }
302- this . scrolledToBottom = isScrolledToBottom ( view . scrollDOM )
309+ let scrollOffset = this . getScrollOffset ( )
310+ if ( this . scrollOffset != scrollOffset ) {
311+ this . scrollAnchorHeight = - 1
312+ this . scrollOffset = scrollOffset
313+ }
314+ this . scrolledToBottom = isScrolledToBottom ( this . scrollParent || view . win )
303315
304316 // Pixel viewport
305317 let pixelViewport = ( this . printing ? fullPixelRange : visiblePixelRange ) ( dom , this . paddingTop )
@@ -581,9 +593,15 @@ export class ViewState {
581593 this . scaler )
582594 }
583595
584- scrollAnchorAt ( scrollTop : number ) {
585- let block = this . lineBlockAtHeight ( scrollTop + 8 )
586- return block . from >= this . viewport . from || this . viewportLines [ 0 ] . top - scrollTop > 200 ? block : this . viewportLines [ 0 ]
596+ getScrollOffset ( ) {
597+ let base = this . scrollParent == this . view . scrollDOM ? this . scrollParent . scrollTop
598+ : ( this . scrollParent ? this . scrollParent . getBoundingClientRect ( ) . top : 0 ) - this . view . contentDOM . getBoundingClientRect ( ) . top
599+ return base * this . scaleY
600+ }
601+
602+ scrollAnchorAt ( scrollOffset : number ) {
603+ let block = this . lineBlockAtHeight ( scrollOffset + 8 )
604+ return block . from >= this . viewport . from || this . viewportLines [ 0 ] . top - scrollOffset > 200 ? block : this . viewportLines [ 0 ]
587605 }
588606
589607 elementAtHeight ( height : number ) : BlockInfo {
0 commit comments