@@ -22,6 +22,7 @@ import { logger } from "matrix-js-sdk/src/logger";
2222import NodeAnimator from "../../../NodeAnimator" ;
2323import { toPx } from "../../../utils/units" ;
2424import MemberAvatar from '../avatars/MemberAvatar' ;
25+ import { READ_AVATAR_SIZE } from "./ReadReceiptGroup" ;
2526
2627export interface IReadReceiptInfo {
2728 top ?: number ;
@@ -101,10 +102,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
101102 return ;
102103 }
103104
104- const avatarNode = this . avatar . current ;
105- rrInfo . top = avatarNode . offsetTop ;
106- rrInfo . right = avatarNode . getBoundingClientRect ( ) . right - avatarNode . offsetParent . getBoundingClientRect ( ) . right ;
107- rrInfo . parent = avatarNode . offsetParent ;
105+ this . buildReadReceiptInfo ( rrInfo ) ;
108106 }
109107
110108 public componentDidMount ( ) : void {
@@ -123,42 +121,85 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
123121 }
124122 }
125123
126- private animateMarker ( ) : void {
127- // treat new RRs as though they were off the top of the screen
128- let oldTop = - 15 ;
124+ private buildReadReceiptInfo ( target : IReadReceiptInfo = { } ) : IReadReceiptInfo {
125+ const element = this . avatar . current ;
126+ // this is the mx_ReadReceiptsGroup_container
127+ const horizontalContainer = element . offsetParent ;
128+ if ( ! horizontalContainer || ! ( horizontalContainer instanceof HTMLElement ) ) {
129+ // this seems to happen sometimes for reasons I don't understand
130+ // the docs for `offsetParent` say it may be null if `display` is
131+ // `none`, but I can't see why that would happen.
132+ logger . warn (
133+ `ReadReceiptMarker for ${ this . props . fallbackUserId } has no valid horizontalContainer` ,
134+ ) ;
129135
130- const oldInfo = this . props . readReceiptInfo ;
131- if ( oldInfo && oldInfo . parent ) {
132- oldTop = oldInfo . top + oldInfo . parent . getBoundingClientRect ( ) . top ;
136+ target . top = 0 ;
137+ target . right = 0 ;
138+ target . parent = null ;
139+ return ;
133140 }
141+ // this is the mx_ReadReceiptsGroup
142+ const verticalContainer = horizontalContainer . offsetParent ;
143+ if ( ! verticalContainer || ! ( verticalContainer instanceof HTMLElement ) ) {
144+ // this seems to happen sometimes for reasons I don't understand
145+ // the docs for `offsetParent` say it may be null if `display` is
146+ // `none`, but I can't see why that would happen.
147+ logger . warn (
148+ `ReadReceiptMarker for ${ this . props . fallbackUserId } has no valid verticalContainer` ,
149+ ) ;
134150
135- const newElement = this . avatar . current ;
136- let startTopOffset ;
137- if ( ! newElement . offsetParent ) {
151+ target . top = 0 ;
152+ target . right = 0 ;
153+ target . parent = null ;
154+ return ;
155+ }
156+
157+ target . top = element . offsetTop ;
158+ target . right = element . getBoundingClientRect ( ) . right - horizontalContainer . getBoundingClientRect ( ) . right ;
159+ target . parent = verticalContainer ;
160+ return target ;
161+ }
162+
163+ private readReceiptPosition ( info : IReadReceiptInfo ) : number {
164+ if ( ! info . parent ) {
138165 // this seems to happen sometimes for reasons I don't understand
139166 // the docs for `offsetParent` say it may be null if `display` is
140167 // `none`, but I can't see why that would happen.
141168 logger . warn (
142- `ReadReceiptMarker for ${ this . props . fallbackUserId } in has no offsetParent` ,
169+ `ReadReceiptMarker for ${ this . props . fallbackUserId } has no offsetParent` ,
143170 ) ;
144- startTopOffset = 0 ;
145- } else {
146- startTopOffset = oldTop - newElement . offsetParent . getBoundingClientRect ( ) . top ;
171+ return 0 ;
147172 }
148173
149- const startStyles = [ ] ;
174+ return info . top + info . parent . getBoundingClientRect ( ) . top ;
175+ }
150176
151- if ( oldInfo && oldInfo . right ) {
177+ private animateMarker ( ) : void {
178+ const oldInfo = this . props . readReceiptInfo ;
179+ const newInfo = this . buildReadReceiptInfo ( ) ;
180+
181+ const newPosition = this . readReceiptPosition ( newInfo ) ;
182+ const oldPosition = oldInfo
152183 // start at the old height and in the old h pos
153- startStyles . push ( { top : startTopOffset + "px" ,
154- right : toPx ( oldInfo . right ) } ) ;
155- }
184+ ? this . readReceiptPosition ( oldInfo )
185+ // treat new RRs as though they were off the top of the screen
186+ : - READ_AVATAR_SIZE ;
156187
157- startStyles . push ( { top : startTopOffset + 'px' , right : '0' } ) ;
188+ const startStyles = [ ] ;
189+ if ( oldInfo && oldInfo . right ) {
190+ startStyles . push ( {
191+ top : oldPosition - newPosition ,
192+ right : oldInfo . right ,
193+ } ) ;
194+ }
195+ startStyles . push ( {
196+ top : oldPosition - newPosition ,
197+ right : 0 ,
198+ } ) ;
158199
159200 this . setState ( {
160201 suppressDisplay : false ,
161- startStyles : startStyles ,
202+ startStyles,
162203 } ) ;
163204 }
164205
0 commit comments