// tslint:disable:react-a11y-anchors import React, { useRef } from 'react'; import is from '@sindresorhus/is'; import * as GoogleChrome from '../util/GoogleChrome'; import * as MIME from '../types/MIME'; import { SessionIconButton, SessionIconType } from './session/icon'; import { Flex } from './basic/Flex'; // useCss has some issues on our setup. so import it directly // tslint:disable-next-line: no-submodule-imports import useUnmount from 'react-use/lib/useUnmount'; import { useEncryptedFileFetch } from '../hooks/useEncryptedFileFetch'; import { useDispatch } from 'react-redux'; import { showLightBox } from '../state/ducks/conversations'; import { useDisableDrag } from '../hooks/useDisableDrag'; const Colors = { TEXT_SECONDARY: '#bbb', ICON_SECONDARY: '#ccc', }; const colorSVG = (url: string, color: string) => { return { WebkitMask: `url(${url}) no-repeat center`, WebkitMaskSize: '100%', backgroundColor: color, }; }; type Props = { contentType: MIME.MIMEType | undefined; objectURL: string; caption?: string; onNext?: () => void; onPrevious?: () => void; onSave?: () => void; }; const CONTROLS_WIDTH = 50; const CONTROLS_SPACING = 10; const styles = { container: { display: 'flex', flexDirection: 'column', position: 'fixed', width: '100vw', height: '100vh', left: 0, zIndex: 5, right: 0, top: 0, bottom: 0, backgroundColor: 'rgba(0, 0, 0, 0.8)', } as React.CSSProperties, mainContainer: { display: 'flex', flexDirection: 'row', flexGrow: 1, paddingTop: 40, paddingLeft: 40, paddingRight: 40, paddingBottom: 0, minHeight: 0, overflow: 'hidden', minWidth: 0, } as React.CSSProperties, objectContainer: { position: 'relative', flexGrow: 1, display: 'inline-flex', justifyContent: 'center', } as React.CSSProperties, objectParentContainer: { flexGrow: 1, textAlign: 'center' as 'center', margin: 'auto', }, object: { flexGrow: 1, flexShrink: 0, maxWidth: '80vw', maxHeight: '80vh', objectFit: 'contain', } as React.CSSProperties, caption: { position: 'absolute', bottom: 0, left: 0, right: 0, textAlign: 'center', color: 'black', padding: '1em', paddingLeft: '3em', paddingRight: '3em', backgroundColor: 'rgba(192, 192, 192, .40)', } as React.CSSProperties, controlsOffsetPlaceholder: { width: CONTROLS_WIDTH, marginRight: CONTROLS_SPACING, flexShrink: 0, }, controls: { width: CONTROLS_WIDTH, flexShrink: 0, display: 'flex', flexDirection: 'column', marginLeft: CONTROLS_SPACING, } as React.CSSProperties, navigationContainer: { flexShrink: 0, display: 'flex', flexDirection: 'row', justifyContent: 'center', padding: 10, } as React.CSSProperties, saveButton: { marginTop: 10, }, iconButtonPlaceholder: { // Dimensions match `.iconButton`: display: 'inline-block', width: 50, height: 50, }, }; interface IconButtonProps { onClick?: () => void; style?: React.CSSProperties; type: 'save' | 'close' | 'previous' | 'next'; } const IconButton = ({ onClick, type }: IconButtonProps) => { const clickHandler = (): void => { if (!onClick) { return; } onClick(); }; let iconRotation = 0; let iconType: SessionIconType = 'chevron'; switch (type) { case 'next': iconRotation = 270; break; case 'previous': iconRotation = 90; break; case 'close': iconType = 'exit'; break; case 'save': iconType = 'upload'; iconRotation = 180; break; default: throw new TypeError(`Invalid button type: ${type}`); } return ( ); }; const IconButtonPlaceholder = () =>
; const Icon = ({ onClick, url, }: { onClick?: (event: React.MouseEvent) => void; url: string; }) => (
); // tslint:disable-next-line: max-func-body-length export const LightboxObject = ({ objectURL, contentType, renderedRef, onObjectClick, }: { objectURL: string; contentType: MIME.MIMEType; renderedRef: React.MutableRefObject; onObjectClick: (event: any) => any; }) => { const { urlToLoad } = useEncryptedFileFetch(objectURL, contentType, false); const isImageTypeSupported = GoogleChrome.isImageTypeSupported(contentType); // auto play video on showing a video attachment useUnmount(() => { if (!renderedRef?.current) { return; } renderedRef.current.pause.pause(); }); const disableDrag = useDisableDrag(); if (isImageTypeSupported) { return ( {window.i18n('lightboxImageAlt')} ); } const isVideoTypeSupported = GoogleChrome.isVideoTypeSupported(contentType); if (isVideoTypeSupported) { if (urlToLoad) { if (renderedRef?.current?.paused) { void renderedRef?.current?.play(); } } return ( ); } const isUnsupportedImageType = !isImageTypeSupported && MIME.isImage(contentType); const isUnsupportedVideoType = !isVideoTypeSupported && MIME.isVideo(contentType); if (isUnsupportedImageType || isUnsupportedVideoType) { const iconUrl = isUnsupportedVideoType ? 'images/video.svg' : 'images/image.svg'; return ; } // tslint:disable-next-line no-console console.log('Lightbox: Unexpected content type', { contentType }); return ; }; export const Lightbox = (props: Props) => { const renderedRef = useRef(null); const dispatch = useDispatch(); const { caption, contentType, objectURL, onNext, onPrevious, onSave } = props; const onObjectClick = (event: any) => { event.stopPropagation(); dispatch(showLightBox(undefined)); }; const onContainerClick = (event: React.MouseEvent) => { if (renderedRef && event.target === renderedRef.current) { return; } dispatch(showLightBox(undefined)); }; return (
{!is.undefined(contentType) ? ( ) : null} {caption ?
{caption}
: null}
{ dispatch(showLightBox(undefined)); }} /> {onSave ? : null}
{onPrevious ? ( ) : ( )} {onNext ? : }
); };