|
| 1 | +// ==LICENSE-BEGIN== |
| 2 | +// Copyright 2017 European Digital Reading Lab. All rights reserved. |
| 3 | +// Licensed to the Readium Foundation under one or more contributor license agreements. |
| 4 | +// Use of this source code is governed by a BSD-style license |
| 5 | +// that can be found in the LICENSE file exposed on Github (readium) in the project repository. |
| 6 | +// ==LICENSE-END== |
| 7 | + |
| 8 | +import * as React from "react"; |
| 9 | +import { IReaderRootState } from "readium-desktop/common/redux/states/renderer/readerRootState"; |
| 10 | +import { useSelector } from "readium-desktop/renderer/common/hooks/useSelector"; |
| 11 | + |
| 12 | +import * as stylesModals from "readium-desktop/renderer/assets/styles/components/modals.scss"; |
| 13 | +import * as stylesButtons from "readium-desktop/renderer/assets/styles/components/buttons.scss"; |
| 14 | + |
| 15 | +import * as Dialog from "@radix-ui/react-dialog"; |
| 16 | +import { useDispatch } from "readium-desktop/renderer/common/hooks/useDispatch"; |
| 17 | +import { readerLocalActionSetImageClick } from "../redux/actions"; |
| 18 | +import classNames from "classnames"; |
| 19 | + |
| 20 | +import SVG from "readium-desktop/renderer/common/components/SVG"; |
| 21 | +import * as QuitIcon from "readium-desktop/renderer/assets/icons/baseline-close-24px.svg"; |
| 22 | + |
| 23 | +import { TransformWrapper, TransformComponent, useControls } from "react-zoom-pan-pinch"; |
| 24 | +import { useTranslator } from "readium-desktop/renderer/common/hooks/useTranslator"; |
| 25 | + |
| 26 | + |
| 27 | +const Controls = () => { |
| 28 | + const { zoomIn, zoomOut, resetTransform } = useControls(); |
| 29 | + |
| 30 | + return ( |
| 31 | + <div style={{position: "absolute", display: "flex", flexDirection: "column", zIndex: 105, top: "42%", right: "10px"}}> |
| 32 | + <button className={stylesButtons.button_nav_primary} onClick={() => zoomIn()}>+</button> |
| 33 | + <button className={stylesButtons.button_nav_primary} onClick={() => zoomOut()}>-</button> |
| 34 | + <button className={stylesButtons.button_nav_primary} onClick={() => resetTransform()}>x</button> |
| 35 | + </div> |
| 36 | + ); |
| 37 | + }; |
| 38 | + |
| 39 | +export const ImageClickManager: React.FC = () => { |
| 40 | + |
| 41 | + const { open, isSVGFragment, HTMLImgSrc_SVGImageHref_SVGFragmentMarkup, altAttributeOf_HTMLImg_SVGImage_SVGFragment, titleAttributeOf_HTMLImg_SVGImage_SVGFragment, ariaLabelAttributeOf_HTMLImg_SVGImage_SVGFragment, naturalWidthOf_HTMLImg_SVGImage, naturalHeightOf_HTMLImg_SVGImage } = useSelector((state: IReaderRootState) => state.img); |
| 42 | + const dispatch = useDispatch(); |
| 43 | + const [__] = useTranslator(); |
| 44 | + |
| 45 | + const scaleX = naturalWidthOf_HTMLImg_SVGImage ? ((window.innerHeight - 50) / naturalWidthOf_HTMLImg_SVGImage) : 1; |
| 46 | + const scaleY = naturalHeightOf_HTMLImg_SVGImage ? ((window.innerWidth - 50) / naturalHeightOf_HTMLImg_SVGImage) : 1; |
| 47 | + let scale = Math.min(scaleX, scaleY); |
| 48 | + if (scale > 1) scale = 1; |
| 49 | + |
| 50 | + return (<> |
| 51 | + |
| 52 | + <Dialog.Root open={open} onOpenChange={(openState: boolean) => { |
| 53 | + if (openState == false) { |
| 54 | + dispatch(readerLocalActionSetImageClick.build()); |
| 55 | + } |
| 56 | + }} |
| 57 | + > |
| 58 | + <Dialog.Portal> |
| 59 | + <div className={stylesModals.modal_dialog_overlay}></div> |
| 60 | + <Dialog.Content style={{ width: "100%", height: "100%", backgroundColor: "unset", border: "unset" }} className={classNames(stylesModals.modal_dialog)} aria-describedby={undefined}> |
| 61 | + <Dialog.Close asChild> |
| 62 | + <button style={{position: "absolute", top: "10px", right: "10px", zIndex: 105}} className={stylesButtons.button_transparency_icon} aria-label={__("accessibility.closeDialog")}> |
| 63 | + <SVG ariaHidden={true} svg={QuitIcon} /> |
| 64 | + </button> |
| 65 | + </Dialog.Close> |
| 66 | + <TransformWrapper initialScale={scale} minScale={scale / 2} maxScale={4 * scale}> |
| 67 | + <Controls /> |
| 68 | + <TransformComponent wrapperStyle={{ width: "100%", height: "100%", minHeight: "inherit" }} > |
| 69 | + <img |
| 70 | + style={{ width: "100%", height: "100%", backgroundColor: "white", color: "black", fill: "currentcolor", stroke: "currentcolor" }} |
| 71 | + src={isSVGFragment ? ("data:image/svg+xml;base64," + Buffer.from(HTMLImgSrc_SVGImageHref_SVGFragmentMarkup).toString("base64")) : HTMLImgSrc_SVGImageHref_SVGFragmentMarkup} |
| 72 | + alt={altAttributeOf_HTMLImg_SVGImage_SVGFragment} |
| 73 | + title={titleAttributeOf_HTMLImg_SVGImage_SVGFragment} |
| 74 | + aria-label={ariaLabelAttributeOf_HTMLImg_SVGImage_SVGFragment} |
| 75 | + tabIndex={0} |
| 76 | + /> |
| 77 | + </TransformComponent> |
| 78 | + </TransformWrapper> |
| 79 | + </Dialog.Content> |
| 80 | + </Dialog.Portal> |
| 81 | + </Dialog.Root> |
| 82 | + </>); |
| 83 | +}; |
0 commit comments