@@ -48,6 +48,7 @@ interface EventsCalendarProps {
4848}
4949
5050// Custom toolbar for < and > month buttons
51+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5152const CustomToolbar : React . FC < ToolbarProps < any , object > > = ( {
5253 label,
5354 onNavigate,
@@ -165,19 +166,59 @@ const EventsCalendar: React.FC<EventsCalendarProps> = ({ events }) => {
165166
166167 const popupWidth = 320 ;
167168 const popupHeight = 200 ;
168- let x = rect . left - containerRect . left + rect . width + 10 ;
169- let y = rect . top - containerRect . top ;
169+
170+ // Calculate all possible positions relative to event
171+ const positions = {
172+ right : { x : rect . right + 10 , y : rect . top } ,
173+ left : { x : rect . left - popupWidth - 10 , y : rect . top } ,
174+ bottom : { x : rect . left , y : rect . bottom + 10 } ,
175+ top : { x : rect . left , y : rect . top - popupHeight - 10 }
176+ } ;
177+
178+ // Score each position based on how well it fits
179+ let bestPosition = null ;
180+ let bestScore = - 1 ;
181+
182+ for ( const [ name , pos ] of Object . entries ( positions ) ) {
183+ let score = 0 ;
184+
185+ // Check if popup fits in viewport
186+ if ( pos . x >= 0 && pos . x + popupWidth <= window . innerWidth ) score += 10 ;
187+ if ( pos . y >= 0 && pos . y + popupHeight <= window . innerHeight ) score += 10 ;
170188
171- // Handle overflow
172- if ( x + popupWidth > containerRect . width ) {
173- x = rect . left - containerRect . left - popupWidth - 10 ;
189+ // Check if popup fits in container
190+ const containerX = pos . x - containerRect . left ;
191+ const containerY = pos . y - containerRect . top ;
192+ if ( containerX >= 0 && containerX + popupWidth <= containerRect . width ) score += 5 ;
193+ if ( containerY >= 0 && containerY + popupHeight <= containerRect . height ) score += 5 ;
194+
195+ // Prefer right and bottom positions for better UX
196+ if ( name === 'right' ) score += 2 ;
197+ if ( name === 'bottom' ) score += 1 ;
198+
199+ if ( score > bestScore ) {
200+ bestScore = score ;
201+ bestPosition = pos ;
202+ }
174203 }
175- if ( y + popupHeight > containerRect . height ) {
176- y = containerRect . height - popupHeight - 10 ;
204+
205+ // Convert to container-relative coordinates or fallback to center
206+ let finalPosition ;
207+ if ( bestPosition && bestScore > 0 ) {
208+ finalPosition = {
209+ x : bestPosition . x - containerRect . left ,
210+ y : bestPosition . y - containerRect . top
211+ } ;
212+ } else {
213+ // Fallback to center if no good position found
214+ finalPosition = {
215+ x : Math . max ( 0 , ( containerRect . width - popupWidth ) / 2 ) ,
216+ y : Math . max ( 0 , ( containerRect . height - popupHeight ) / 2 )
217+ } ;
177218 }
178219
179220 setSelectedEvent ( event ) ;
180- setPopupPosition ( { x , y } ) ;
221+ setPopupPosition ( finalPosition ) ;
181222 } ;
182223
183224 const closePopup = ( ) => {
0 commit comments