forked from Wolox/react-chat-widget
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Wolox#181 from Here21/dev/fullScreen
Image fullscreen preview
- Loading branch information
Showing
28 changed files
with
571 additions
and
47 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
src/components/Widget/components/FullScreenPreview/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import React, { useEffect, ReactNode } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
import usePreview from './usePreview'; | ||
import usePortal from './usePortal'; | ||
import './styles.scss'; | ||
import { GlobalState } from '../../../../store/types'; | ||
import { closeFullscreenPreview } from '../../../../store/actions'; | ||
|
||
const close = require('../../../../../assets/close.svg') as string; | ||
const plus = require('../../../../../assets/plus.svg') as string; | ||
const minus = require('../../../../../assets/minus.svg') as string; | ||
const zoomIn = require('../../../../../assets/zoom-in.svg') as string; | ||
const zoomOut = require('../../../../../assets/zoom-out.svg') as string; | ||
|
||
type Props = { | ||
fullScreenMode?: boolean; | ||
zoomStep?: number | ||
} | ||
|
||
export default function FullScreenPreview({ fullScreenMode, zoomStep }:Props) { | ||
const { | ||
state, | ||
initFileSize, | ||
onZoomIn, | ||
onZoomOut, | ||
onResizePageZoom | ||
} = usePreview(zoomStep); | ||
|
||
const dispatch = useDispatch(); | ||
const { src, alt, width, height, visible } = useSelector((state: GlobalState) => ({ | ||
src: state.preview.src, | ||
alt: state.preview.alt, | ||
width: state.preview.width, | ||
height: state.preview.height, | ||
visible: state.preview.visible | ||
})); | ||
|
||
useEffect(() => { | ||
if(src) { | ||
initFileSize(width, height); | ||
} | ||
}, [src]) | ||
|
||
const pDom = usePortal() | ||
|
||
const onClosePreview = () => { | ||
dispatch(closeFullscreenPreview()) | ||
} | ||
|
||
const childNode: ReactNode = ( | ||
<div className="rcw-previewer-container"> | ||
<div className="rcw-previewer-veil"> | ||
<img {...state.layout} src={src} className="rcw-previewer-image" alt={alt} /> | ||
</div> | ||
<button | ||
className="rcw-previewer-button rcw-previewer-close-button" | ||
onClick={onClosePreview} | ||
> | ||
<img src={close} className="rcw-previewer-icon" /> | ||
</button> | ||
<div className="rcw-previewer-tools"> | ||
<button | ||
className="rcw-previewer-button" | ||
onClick={onResizePageZoom} | ||
> | ||
<img | ||
src={state.zoom ? zoomOut : zoomIn} | ||
className="rcw-previewer-icon" | ||
alt="reset zoom" | ||
/> | ||
</button> | ||
|
||
<button | ||
className="rcw-previewer-button" | ||
onClick={onZoomIn} | ||
> | ||
<img src={plus} className="rcw-previewer-icon" alt="zoom in"/> | ||
</button> | ||
<button | ||
className="rcw-previewer-button" | ||
onClick={onZoomOut} | ||
> | ||
<img src={minus} className="rcw-previewer-icon" alt="zoom out"/> | ||
</button> | ||
</div> | ||
</div> | ||
) | ||
|
||
return visible ? ReactDOM.createPortal(childNode, pDom) : null; | ||
} |
60 changes: 60 additions & 0 deletions
60
src/components/Widget/components/FullScreenPreview/styles.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
@import 'variables/colors'; | ||
|
||
.rcw-previewer-container { | ||
width: 100vw; | ||
height: 100vh; | ||
background: rgba(0, 0, 0, 0.75); | ||
overflow: hidden; | ||
position: fixed; | ||
z-index: 9999; | ||
left: 0; | ||
top: 0; | ||
|
||
.rcw-previewer-image { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
right: 0; | ||
bottom: 0; | ||
margin: auto; | ||
transition: all 0.3s ease; | ||
} | ||
|
||
.rcw-previewer-tools { | ||
position: fixed; | ||
right: 16px; | ||
bottom: 16px; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.rcw-previewer-button { | ||
padding: 0; | ||
margin: 16px; | ||
box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.3); | ||
border-radius: 50%; | ||
width: 32px; | ||
height: 32px; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
outline: none; | ||
background-color: $white; | ||
border: none; | ||
} | ||
|
||
.rcw-previewer-close-button { | ||
position: absolute; | ||
right: 0; | ||
top: 0; | ||
} | ||
|
||
.rcw-previewer-veil { | ||
width: 100%; | ||
height: 100%; | ||
overflow: scroll; | ||
position: relative; | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/components/Widget/components/FullScreenPreview/usePortal.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { useRef, useEffect } from 'react'; | ||
|
||
function createRootElement(id: string):HTMLDivElement { | ||
const rootContainer = document.createElement('div'); | ||
rootContainer.setAttribute('id', id); | ||
return rootContainer; | ||
} | ||
|
||
function addRootElement(rootElem: HTMLDivElement):void { | ||
document.body.appendChild(rootElem); | ||
} | ||
|
||
function usePortal():HTMLDivElement { | ||
const rootElemRef = useRef<HTMLElement | null>(null); | ||
|
||
useEffect(() => { | ||
// Look for existing target dom element to append to | ||
const existingParent: HTMLDivElement | null = document.querySelector('#rcw-image-preview'); | ||
// Parent is either a new root or the existing dom element | ||
const parentElem: HTMLDivElement = existingParent || createRootElement('#rcw-image-preview'); | ||
|
||
// If there is no existing DOM element, add a new one. | ||
if (!existingParent) { | ||
addRootElement(parentElem); | ||
} | ||
|
||
// Add the detached element to the parent | ||
if(rootElemRef.current) { | ||
parentElem.appendChild(rootElemRef.current); | ||
} | ||
|
||
return function removeElement() { | ||
if(rootElemRef.current) { | ||
rootElemRef.current.remove(); | ||
} | ||
if (parentElem.childNodes.length === -1) { | ||
parentElem.remove(); | ||
} | ||
}; | ||
}, []); | ||
|
||
function getRootElem():HTMLDivElement { | ||
if (!rootElemRef.current) { | ||
rootElemRef.current = document.createElement('div'); | ||
} | ||
return rootElemRef.current as HTMLDivElement; | ||
} | ||
|
||
return getRootElem(); | ||
} | ||
|
||
export default usePortal; |
Oops, something went wrong.