@@ -17,6 +17,7 @@ interface UseAnnotationTooltipProps {
17
17
annotation : Annotation ;
18
18
onOpenChange ?: ( open : boolean ) => void ;
19
19
position ?: "top" | "bottom" | "left" | "right" ;
20
+ isOpen ?: boolean ;
20
21
}
21
22
22
23
interface UseAnnotationTooltipReturn {
@@ -43,20 +44,25 @@ export const useAnnotationTooltip = ({
43
44
annotation,
44
45
onOpenChange,
45
46
position = "top" ,
47
+ isOpen : controlledIsOpen ,
46
48
} : UseAnnotationTooltipProps ) : UseAnnotationTooltipReturn => {
47
49
// Show tooltip immediately if it's a new annotation
48
50
const isNewAnnotation = Date . now ( ) - new Date ( annotation . createdAt ) . getTime ( ) < 1000 ;
49
- const [ isOpen , setIsOpen ] = useState ( isNewAnnotation ) ;
51
+ const [ isPositionCalculated , setIsPositionCalculated ] = useState ( false ) ;
52
+ const [ isOpen , setIsOpen ] = useState ( false ) ;
50
53
const viewportRef = usePdf ( ( state ) => state . viewportRef ) ;
51
54
const scale = usePdf ( ( state ) => state . zoom ) ;
52
55
56
+ // Only show if position is calculated or externally controlled
57
+ const effectiveIsOpen = ( ( isOpen && isPositionCalculated ) || controlledIsOpen ) ?? false ;
58
+
53
59
const {
54
60
refs,
55
61
floatingStyles,
56
62
context,
57
63
} = useFloating ( {
58
64
placement : position ,
59
- open : isOpen ,
65
+ open : effectiveIsOpen ,
60
66
onOpenChange : ( open ) => {
61
67
setIsOpen ( open ) ;
62
68
onOpenChange ?.( open ) ;
@@ -77,22 +83,31 @@ export const useAnnotationTooltip = ({
77
83
const { getReferenceProps, getFloatingProps } = useInteractions ( [ dismiss ] ) ;
78
84
79
85
const updateTooltipPosition = useCallback ( ( ) => {
80
- if ( ! annotation . highlights . length ) return ;
86
+ if ( ! annotation . highlights . length ) {
87
+ setIsPositionCalculated ( false ) ;
88
+ return ;
89
+ }
81
90
82
91
const highlightRects = annotation . highlights ;
83
92
let minLeft = Infinity ;
84
93
let maxRight = - Infinity ;
85
94
let minTop = Infinity ;
86
95
let maxBottom = - Infinity ;
87
96
88
- refs . setReference ( {
89
- getBoundingClientRect ( ) {
90
- const viewportElement = viewportRef . current ;
91
- if ( ! viewportElement ) return defaultRect ;
97
+ const viewportElement = viewportRef . current ;
98
+ if ( ! viewportElement ) {
99
+ setIsPositionCalculated ( false ) ;
100
+ return ;
101
+ }
92
102
93
- const pageElement = viewportElement . querySelector ( `[data-page-number="${ annotation . pageNumber } "]` ) ;
94
- if ( ! pageElement ) return defaultRect ;
103
+ const pageElement = viewportElement . querySelector ( `[data-page-number="${ annotation . pageNumber } "]` ) ;
104
+ if ( ! pageElement ) {
105
+ setIsPositionCalculated ( false ) ;
106
+ return ;
107
+ }
95
108
109
+ refs . setReference ( {
110
+ getBoundingClientRect ( ) {
96
111
const pageRect = pageElement . getBoundingClientRect ( ) ;
97
112
98
113
// Calculate the bounding box in viewport coordinates using the PDF scale
@@ -136,11 +151,25 @@ export const useAnnotationTooltip = ({
136
151
} ,
137
152
contextElement : viewportRef . current || undefined ,
138
153
} ) ;
139
- } , [ annotation . highlights , annotation . pageNumber , refs , viewportRef , scale ] ) ;
154
+
155
+ setIsPositionCalculated ( true ) ;
156
+
157
+ // If it's a new annotation, show it once position is calculated
158
+ if ( isNewAnnotation ) {
159
+ setIsOpen ( true ) ;
160
+ }
161
+ } , [ annotation . highlights , annotation . pageNumber , refs , viewportRef , scale , isNewAnnotation ] ) ;
140
162
141
163
useEffect ( ( ) => {
142
164
const viewport = viewportRef . current ;
143
- updateTooltipPosition ( ) ;
165
+
166
+ // Reset position calculated state when scale changes
167
+ setIsPositionCalculated ( false ) ;
168
+
169
+ // Update position with RAF to ensure DOM is ready
170
+ requestAnimationFrame ( ( ) => {
171
+ updateTooltipPosition ( ) ;
172
+ } ) ;
144
173
145
174
const handleScroll = ( ) => {
146
175
requestAnimationFrame ( updateTooltipPosition ) ;
@@ -164,10 +193,10 @@ export const useAnnotationTooltip = ({
164
193
}
165
194
window . removeEventListener ( "resize" , handleResize ) ;
166
195
} ;
167
- } , [ updateTooltipPosition , viewportRef ] ) ;
196
+ } , [ updateTooltipPosition , viewportRef , scale , controlledIsOpen ] ) ;
168
197
169
198
return {
170
- isOpen,
199
+ isOpen : effectiveIsOpen ,
171
200
setIsOpen,
172
201
refs,
173
202
floatingStyles,
0 commit comments