@@ -18,8 +18,13 @@ interface ImageLightboxProps
18
18
width ?: number ;
19
19
}
20
20
21
- const getImageUrl = ( src : string , imgPath : string ) : string =>
22
- isExternalImage ( src ) ? src : imgPath ;
21
+ const getImageUrl = ( src : string , imgPath : string ) : string => {
22
+ if ( isExternalImage ( src ) ) {
23
+ // Normalize protocol-relative URLs to use https:
24
+ return src . startsWith ( '//' ) ? `https:${ src } ` : src ;
25
+ }
26
+ return imgPath ;
27
+ } ;
23
28
24
29
type ValidDimensions = {
25
30
height : number ;
@@ -57,25 +62,32 @@ export function ImageLightbox({
57
62
! ! dimensions && ( ! isExternalImage ( src ) || isAllowedRemoteImage ( src ) ) ;
58
63
59
64
const openInNewTab = ( ) => {
60
- window . open ( getImageUrl ( src , imgPath ) , '_blank' ) ;
65
+ window . open ( getImageUrl ( src , imgPath ) , '_blank' , 'noopener,noreferrer' ) ;
61
66
} ;
62
67
63
68
const handleClick = ( e : React . MouseEvent ) => {
64
69
// Middle-click or Ctrl/Cmd+click opens in new tab
65
70
if ( e . button === 1 || e . ctrlKey || e . metaKey ) {
66
71
e . preventDefault ( ) ;
72
+ e . stopPropagation ( ) ;
67
73
openInNewTab ( ) ;
68
74
return ;
69
75
}
70
- // Regular click falls through to Dialog.Trigger
76
+ // Regular click opens lightbox - let it bubble to Dialog.Trigger
71
77
} ;
72
78
73
79
const handleKeyDown = ( e : React . KeyboardEvent ) => {
74
- if ( ( e . key === 'Enter' || e . key === ' ' ) && ( e . ctrlKey || e . metaKey ) ) {
80
+ if ( e . key === 'Enter' || e . key === ' ' ) {
81
+ if ( e . ctrlKey || e . metaKey ) {
82
+ e . preventDefault ( ) ;
83
+ e . stopPropagation ( ) ;
84
+ openInNewTab ( ) ;
85
+ return ;
86
+ }
87
+ // Regular Enter/Space should open lightbox
75
88
e . preventDefault ( ) ;
76
- openInNewTab ( ) ;
89
+ setOpen ( true ) ;
77
90
}
78
- // Regular Enter/Space falls through to Dialog.Trigger
79
91
} ;
80
92
81
93
// Filter out props that are incompatible with Next.js Image component
0 commit comments