parent
2a0ca26c8c
commit
45d054571d
9 changed files with 21 additions and 624 deletions
@ -1,293 +0,0 @@ |
|||||||
import React, { useState, useEffect, useCallback, useRef } from 'react' |
|
||||||
import { Book, Rendition } from "epubjs"; |
|
||||||
// style
|
|
||||||
import EpubViewerWrapper from 'modules/epubViewer/style' |
|
||||||
// types
|
|
||||||
import { EpubViewerProps, ViewerRef } from 'types' |
|
||||||
import Toc from 'types/toc' |
|
||||||
import Loc from 'types/loc' |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* EpubViewer Module |
|
||||||
* @class |
|
||||||
* @param props |
|
||||||
* @param props.url Epub path |
|
||||||
* @param props.epubFileOptions Epub file option |
|
||||||
* @param props.epubOptions Epub viewer option |
|
||||||
* @param props.style Epub Wrapper style |
|
||||||
* @param props.location Epub CFI or href |
|
||||||
* @param props.bookChanged Run when book changed |
|
||||||
* @param props.rendtionChanged Run when rendition changed |
|
||||||
* @param props.pageChanged Run when page changed |
|
||||||
* @param props.tocChanged Run when toc changed |
|
||||||
* @param props.selectionChanged Run when selected |
|
||||||
* @param props.loadingView Loading Component |
|
||||||
* @param ref Viewer ref |
|
||||||
*/ |
|
||||||
const EpubViewer = ({ |
|
||||||
url,
|
|
||||||
epubFileOptions,
|
|
||||||
epubOptions, |
|
||||||
style, |
|
||||||
location, |
|
||||||
bookChanged, |
|
||||||
rendtionChanged, |
|
||||||
pageChanged, |
|
||||||
tocChanged, |
|
||||||
selectionChanged, |
|
||||||
loadingView, |
|
||||||
}: EpubViewerProps, ref: React.RefObject<ViewerRef> | any) => { |
|
||||||
// TODO Fix the ref type correctly instead 'any' type.
|
|
||||||
const [isLoaded, setIsLoaded] = useState(false); |
|
||||||
|
|
||||||
const [book, setBook] = useState<Book | null>(null); |
|
||||||
|
|
||||||
const [rendition, setRendition] = useState<Rendition | null>(null); |
|
||||||
|
|
||||||
const [toc, setToc] = useState<Toc[]>([]); |
|
||||||
|
|
||||||
const currentCfi = useRef<string>(''); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Init Book |
|
||||||
* @method |
|
||||||
* - Set book state |
|
||||||
* - Set Epub path state |
|
||||||
* - Set isLoaded state |
|
||||||
* - Set toc state |
|
||||||
*/ |
|
||||||
const initBook = () => { |
|
||||||
if (book) { |
|
||||||
book.destroy(); |
|
||||||
} |
|
||||||
|
|
||||||
const book_ = new Book(url, epubFileOptions); |
|
||||||
setBook(book_); |
|
||||||
|
|
||||||
bookChanged && bookChanged(book_); |
|
||||||
|
|
||||||
book_.loaded.navigation.then(({ toc }) => { |
|
||||||
const toc_: Toc[] = toc.map(t => ({
|
|
||||||
label: t.label,
|
|
||||||
href: t.href
|
|
||||||
})); |
|
||||||
|
|
||||||
setIsLoaded(true); |
|
||||||
setToc(toc_); |
|
||||||
tocChanged && tocChanged(toc_); |
|
||||||
initRendition(book_); |
|
||||||
}); |
|
||||||
|
|
||||||
// Init Location & Pagination
|
|
||||||
book_.ready.then(function() { |
|
||||||
const stored = localStorage.getItem(book_.key() + '-locations'); |
|
||||||
if (stored) { |
|
||||||
return book_.locations.load(stored); |
|
||||||
} else { |
|
||||||
return book_.locations.generate(1024); |
|
||||||
} |
|
||||||
}).then(() => { |
|
||||||
localStorage.setItem(book_.key() + '-locations', book_.locations.save()); |
|
||||||
}); |
|
||||||
}; |
|
||||||
|
|
||||||
/** |
|
||||||
* Init Rendition |
|
||||||
* @method |
|
||||||
* - Init iframe tag on DOM element |
|
||||||
* - Set rendition |
|
||||||
* - Set start page |
|
||||||
*/ |
|
||||||
const initRendition = (book_: Book) => { |
|
||||||
const node = ref.current; |
|
||||||
if (!node || !book_) return; |
|
||||||
|
|
||||||
const rendition_ = book_.renderTo(node, { |
|
||||||
width: "100%", |
|
||||||
height: "100%", |
|
||||||
...epubOptions |
|
||||||
}); |
|
||||||
setRendition(rendition_); |
|
||||||
|
|
||||||
rendtionChanged && rendtionChanged(rendition_); |
|
||||||
|
|
||||||
if(typeof location === "string") { |
|
||||||
rendition_.display(location); |
|
||||||
} else if(toc.length > 0 && toc[0].href) { |
|
||||||
rendition_.display(toc[0].href); |
|
||||||
} else { |
|
||||||
rendition_.display(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Move page |
|
||||||
* @method |
|
||||||
* @param type direction |
|
||||||
*/ |
|
||||||
const movePage = useCallback((type: "PREV" | "NEXT") => { |
|
||||||
if (!rendition) return; |
|
||||||
if (type === "PREV") rendition.prev(); |
|
||||||
else rendition.next(); |
|
||||||
}, [rendition]); |
|
||||||
|
|
||||||
/** |
|
||||||
* Move page by arrow key |
|
||||||
* @method |
|
||||||
* @param props Keyboard Event |
|
||||||
* @param props.key
|
|
||||||
*/ |
|
||||||
const handleKeyPress = useCallback(({ key }: any) => { |
|
||||||
key && key === "ArrowLeft" && movePage("PREV"); |
|
||||||
key && key === "ArrowRight" && movePage("NEXT"); |
|
||||||
}, [movePage]); |
|
||||||
|
|
||||||
/** |
|
||||||
* Run when location changed |
|
||||||
* @method |
|
||||||
* @param loc |
|
||||||
* - Set location state |
|
||||||
* - Run 'locationChanged()' through startCFI |
|
||||||
*/ |
|
||||||
const onLocationChange = useCallback((loc: Loc) => { |
|
||||||
const startCfi = loc && loc.start; |
|
||||||
const endCfi = loc && loc.end; |
|
||||||
const base = loc && loc.start.slice(8).split('!')[0]; |
|
||||||
|
|
||||||
if (!book) return; |
|
||||||
|
|
||||||
const spineItem = book.spine.get(startCfi); |
|
||||||
const navItem = book.navigation.get(spineItem.href); |
|
||||||
const chapterName = navItem && navItem.label.trim(); |
|
||||||
|
|
||||||
const locations: any = book.locations; |
|
||||||
const currentPage = locations.locationFromCfi(startCfi); |
|
||||||
const totalPage = locations.total; |
|
||||||
|
|
||||||
pageChanged && pageChanged({ |
|
||||||
chapterName,
|
|
||||||
currentPage,
|
|
||||||
totalPage,
|
|
||||||
startCfi,
|
|
||||||
endCfi, |
|
||||||
base |
|
||||||
}); |
|
||||||
|
|
||||||
currentCfi.current = startCfi; |
|
||||||
}, [book, pageChanged]); |
|
||||||
|
|
||||||
/** |
|
||||||
* Highlight function |
|
||||||
* @param cfiRange Selecton CFIRange |
|
||||||
* @param color Highlight color |
|
||||||
* @param callback Highlight callback function when click it |
|
||||||
*/ |
|
||||||
const onHighlight = useCallback(( |
|
||||||
cfiRange: string,
|
|
||||||
callback: (e: any) => void, |
|
||||||
color?: string |
|
||||||
) => { |
|
||||||
if (!rendition) return; |
|
||||||
|
|
||||||
rendition.annotations.remove(cfiRange, 'highlight'); |
|
||||||
rendition.annotations.highlight( |
|
||||||
cfiRange,
|
|
||||||
{},
|
|
||||||
callback,
|
|
||||||
"epub-highlight", |
|
||||||
{ 'fill': color || '#fdf183' } |
|
||||||
); |
|
||||||
}, [rendition]); |
|
||||||
|
|
||||||
/** |
|
||||||
* Register viewer control function |
|
||||||
* @method |
|
||||||
* - REF.CURRENT.prevPage() : Move prev page |
|
||||||
* - REF.CURRENT.nextPage() : Move next page |
|
||||||
* - REF.CURRENT.getCurrentCfi() : Get current CFI |
|
||||||
* - REF.CURRENT.onHighlight(): Set highlight |
|
||||||
* - REF.CURRENT.offHighlight(): Remove specific highliht |
|
||||||
* - REF.CURRENT.seLocation(): Move to specific cfi or href |
|
||||||
*/ |
|
||||||
const registerGlobalFunc = useCallback(() => { |
|
||||||
if (!ref.current) return; |
|
||||||
if (movePage) { |
|
||||||
ref.current.prevPage = () => movePage("PREV"); |
|
||||||
ref.current.nextPage = () => movePage("NEXT"); |
|
||||||
} |
|
||||||
ref.current.getCurrentCfi = () => currentCfi.current; |
|
||||||
if (onHighlight) { |
|
||||||
ref.current.onHighlight = onHighlight; |
|
||||||
} |
|
||||||
if (rendition) { |
|
||||||
ref.current.offHighlight = (cfiRange: string) => rendition.annotations.remove(cfiRange, 'highlight'); |
|
||||||
ref.current.setLocation = (location: string) => rendition.display(location); |
|
||||||
} |
|
||||||
}, [ref, rendition, movePage, onHighlight]); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Ref checker */ |
|
||||||
useEffect(() => { |
|
||||||
if (!ref) { |
|
||||||
throw new Error("[React-Epub-Viewer] Put a ref argument that has a ViewerRef type."); |
|
||||||
} |
|
||||||
}, [ref]); |
|
||||||
|
|
||||||
/** Epub Init */ |
|
||||||
/* eslint-disable */ |
|
||||||
useEffect(() => { |
|
||||||
if (!url) return; |
|
||||||
initBook(); |
|
||||||
}, [url]); |
|
||||||
/* eslint-enable */ |
|
||||||
|
|
||||||
/** |
|
||||||
* Emit Viewer Event |
|
||||||
* - Register move event |
|
||||||
* - Register location changed event |
|
||||||
* - Register selection event |
|
||||||
*/ |
|
||||||
/* eslint-disable */ |
|
||||||
useEffect(() => { |
|
||||||
if (!rendition) return; |
|
||||||
|
|
||||||
// Emit global control function
|
|
||||||
registerGlobalFunc(); |
|
||||||
|
|
||||||
document.addEventListener('keyup', handleKeyPress, false); |
|
||||||
rendition.on("keyup", handleKeyPress); |
|
||||||
rendition.on("locationChanged", onLocationChange); |
|
||||||
selectionChanged && rendition.on('selected', selectionChanged); |
|
||||||
|
|
||||||
return (() => { |
|
||||||
document.removeEventListener('keyup', handleKeyPress, false); |
|
||||||
rendition.off("keyup", handleKeyPress); |
|
||||||
rendition.off("locationChanged", onLocationChange); |
|
||||||
selectionChanged && rendition.off('selected', selectionChanged); |
|
||||||
}); |
|
||||||
}, [ |
|
||||||
rendition, |
|
||||||
registerGlobalFunc, |
|
||||||
handleKeyPress |
|
||||||
]); |
|
||||||
/* eslint-enable */ |
|
||||||
|
|
||||||
/** Display page by changed location */ |
|
||||||
useEffect(() => { |
|
||||||
if (!location || !rendition) return; |
|
||||||
|
|
||||||
rendition.display(location); |
|
||||||
}, [location, rendition]); |
|
||||||
|
|
||||||
|
|
||||||
return (<> |
|
||||||
{!isLoaded && loadingView} |
|
||||||
<EpubViewerWrapper ref={ref} style={style} /> |
|
||||||
</>); |
|
||||||
} |
|
||||||
|
|
||||||
export default React.forwardRef(EpubViewer) |
|
@ -1,15 +0,0 @@ |
|||||||
import styled from 'styled-components' |
|
||||||
|
|
||||||
const EpubViewerWrapper = styled.div` |
|
||||||
width: 100%; |
|
||||||
box-sizing: border-box; |
|
||||||
margin: 0 auto; |
|
||||||
|
|
||||||
& > div { |
|
||||||
&::-webkit-scrollbar { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
} |
|
||||||
`;
|
|
||||||
|
|
||||||
export default EpubViewerWrapper |
|
@ -1,4 +0,0 @@ |
|||||||
import ReactEpubViewer from 'modules/reactViewer/ReactViewer' |
|
||||||
import EpubViewer from 'modules/epubViewer/EpubViewer'; |
|
||||||
|
|
||||||
export { EpubViewer, ReactEpubViewer }; |
|
@ -1,292 +0,0 @@ |
|||||||
import React, { useState, useEffect, useRef, useCallback, useMemo } from "react" |
|
||||||
import { Book, Rendition, Contents } from "epubjs" |
|
||||||
// modules
|
|
||||||
import EpubViewer from "modules/epubViewer/EpubViewer" |
|
||||||
// components
|
|
||||||
import LoadingView from 'LoadingView' |
|
||||||
// utils
|
|
||||||
import { debounce, timeFormatter } from 'lib/utils/commonUtil' |
|
||||||
// styles
|
|
||||||
import viewerDefaultStyles from 'modules/reactViewer/viewerStyle' |
|
||||||
// types
|
|
||||||
import { ReactViewerProps, ViewerRef } from 'types' |
|
||||||
import BookType, { BookStyle, BookOption } from 'types/book' |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Epub React Viewer Module |
|
||||||
* @class |
|
||||||
* @param props |
|
||||||
* @param props.url Epub file path |
|
||||||
* @param props.viewerLayout Viewer layout |
|
||||||
* @param props.viewerStyle Viewer style |
|
||||||
* @param props.viewerOption Viewer option |
|
||||||
* @param props.onBookInfoChange Run when book information changed |
|
||||||
* @param props.onPageChange Run when page changed |
|
||||||
* @param props.onTocChange Run when toc changed |
|
||||||
* @param props.onSelection Run when selected |
|
||||||
* @param props.loadingView Loading component |
|
||||||
* @param ref Viewer ref |
|
||||||
*/ |
|
||||||
const ReactViewer = ({
|
|
||||||
url, |
|
||||||
viewerLayout, |
|
||||||
viewerStyle, |
|
||||||
viewerOption, |
|
||||||
onBookInfoChange, |
|
||||||
onPageChange, |
|
||||||
onTocChange, |
|
||||||
onSelection, |
|
||||||
loadingView |
|
||||||
}: ReactViewerProps, ref: React.RefObject<ViewerRef> | any) => { |
|
||||||
// TODO Fix the ref type correctly instead 'any' type.
|
|
||||||
const [book, setBook] = useState<Book | null>(null); |
|
||||||
|
|
||||||
const [rendition, setRendition] = useState<Rendition | null>(null); |
|
||||||
|
|
||||||
const [layoutStyle, setLayoutStyle] = useState<Object>({}); |
|
||||||
|
|
||||||
const [bookStyle, setBookStyle] = useState<BookStyle>({ |
|
||||||
fontFamily: 'Origin', |
|
||||||
fontSize: 18, |
|
||||||
lineHeight: 1.4, |
|
||||||
marginHorizontal: 15, |
|
||||||
marginVertical: 5 |
|
||||||
}); |
|
||||||
|
|
||||||
const [bookOption, setBookOption] = useState<BookOption>({ |
|
||||||
flow: "paginated", |
|
||||||
resizeOnOrientationChange: true, |
|
||||||
spread: "auto" |
|
||||||
}); |
|
||||||
|
|
||||||
const currentSelection = useRef<{cfiRange:string, contents:Contents | null}>({ |
|
||||||
cfiRange: '', |
|
||||||
contents: null |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Run book changed |
|
||||||
* @method |
|
||||||
* @param book Epub Book |
|
||||||
*/ |
|
||||||
const bookChanged = (book: Book) => setBook(book); |
|
||||||
|
|
||||||
/** |
|
||||||
* Run rendition changed |
|
||||||
* @method |
|
||||||
* @param rendition Epub Rendition |
|
||||||
*/ |
|
||||||
const rendtionChanged = (rendition: Rendition) => setRendition(rendition); |
|
||||||
|
|
||||||
/** |
|
||||||
* Run selection changed [Debounce] |
|
||||||
* @method |
|
||||||
* @param cfiRange CFIRange |
|
||||||
* @param contents Selection Epub Contents |
|
||||||
*/ |
|
||||||
const selectionChanged = (cfiRange: string, contents: Contents) => { |
|
||||||
currentSelection.current = { cfiRange, contents }; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Viewer resizing function |
|
||||||
* @method |
|
||||||
*/ |
|
||||||
const onResize = useMemo(() => debounce(250, () => { |
|
||||||
if (!rendition) return; |
|
||||||
|
|
||||||
const viewerLayout_ = viewerLayout || { |
|
||||||
MIN_VIEWER_WIDTH: 600, |
|
||||||
MIN_VIEWER_HEIGHT: 300, |
|
||||||
VIEWER_HEADER_HEIGHT: 0, |
|
||||||
VIEWER_FOOTER_HEIGHT: 0, |
|
||||||
VIEWER_SIDEMENU_WIDTH: 0 |
|
||||||
}; |
|
||||||
|
|
||||||
const { innerWidth: win_w, innerHeight: win_h } = window; |
|
||||||
const componentHeight = viewerLayout_.VIEWER_HEADER_HEIGHT + viewerLayout_.VIEWER_FOOTER_HEIGHT; |
|
||||||
const w = win_w - ~~((win_w - viewerLayout_.MIN_VIEWER_WIDTH) / 100 * bookStyle.marginHorizontal); |
|
||||||
const h = bookOption.flow === "scrolled-doc" |
|
||||||
? win_h - componentHeight |
|
||||||
: win_h - componentHeight - ~~((win_h - componentHeight - viewerLayout_.MIN_VIEWER_HEIGHT) / 100 * bookStyle.marginVertical); |
|
||||||
const marginTop = bookOption.flow === "scrolled-doc" |
|
||||||
? "" |
|
||||||
: `${~~((win_h - componentHeight - viewerLayout_.MIN_VIEWER_HEIGHT) / 100 * bookStyle.marginVertical) / 2}px`; |
|
||||||
|
|
||||||
setLayoutStyle(l => ({ |
|
||||||
...l, |
|
||||||
width: w, |
|
||||||
height: h, |
|
||||||
marginTop |
|
||||||
})); |
|
||||||
|
|
||||||
try { |
|
||||||
rendition.resize(w, h); |
|
||||||
} catch { } |
|
||||||
}), [ |
|
||||||
rendition, |
|
||||||
viewerLayout, |
|
||||||
bookStyle.marginHorizontal, |
|
||||||
bookStyle.marginVertical, |
|
||||||
bookOption.flow |
|
||||||
]); |
|
||||||
|
|
||||||
/** |
|
||||||
* Selection Event, run when run mouseup event |
|
||||||
* @method <br/> |
|
||||||
* - Fire after the Epubjs selected event. [about 300ms] |
|
||||||
*/ |
|
||||||
const onSelected = useCallback(async () => { |
|
||||||
if (!ref.current) return; |
|
||||||
|
|
||||||
const iframe = ref.current.querySelector('iframe'); |
|
||||||
if (!iframe) return; |
|
||||||
|
|
||||||
const iframeWin = iframe.contentWindow; |
|
||||||
if (!iframeWin) return; |
|
||||||
|
|
||||||
const selection_ = iframeWin.getSelection(); |
|
||||||
if (!selection_) return; |
|
||||||
|
|
||||||
const selectionText = selection_.toString(); |
|
||||||
if (selectionText === "") return; |
|
||||||
|
|
||||||
const cfiRange: string = await new Promise(resolve =>
|
|
||||||
setTimeout(() => resolve(currentSelection.current.cfiRange), 350) |
|
||||||
); |
|
||||||
if (!cfiRange) return; |
|
||||||
|
|
||||||
const contents = currentSelection.current.contents; |
|
||||||
if (!contents) return; |
|
||||||
|
|
||||||
onSelection && onSelection(cfiRange, contents); |
|
||||||
}, [ref, onSelection]); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Ref checker */ |
|
||||||
useEffect(() => { |
|
||||||
if (!ref) { |
|
||||||
throw new Error("[React-Epub-Viewer] Put a ref argument that has a ViewerRef type."); |
|
||||||
} |
|
||||||
}, [ref]); |
|
||||||
|
|
||||||
/** Epub parsing */ |
|
||||||
// TODO Fix the infinite re-rendering issue, when inlcude `onBookInfoChange` to dependencies array.
|
|
||||||
/* eslint-disable */ |
|
||||||
useEffect(() => { |
|
||||||
if (!book) return; |
|
||||||
|
|
||||||
Promise.all([ |
|
||||||
book.loaded.metadata, |
|
||||||
book.opened |
|
||||||
]) |
|
||||||
.then(([metaData, bookData]: any[]) => { |
|
||||||
const newBookData: BookType = { |
|
||||||
coverURL: bookData.archive.urlCache[bookData.cover], |
|
||||||
title: metaData.title, |
|
||||||
description: metaData.description, |
|
||||||
published_date: timeFormatter(new Date(metaData.pubdate)), |
|
||||||
modified_date: timeFormatter(new Date(metaData.modified_date)), |
|
||||||
author: metaData.creator, |
|
||||||
publisher: metaData.publisher, |
|
||||||
language: metaData.language |
|
||||||
} |
|
||||||
|
|
||||||
onBookInfoChange && onBookInfoChange(newBookData); |
|
||||||
}) |
|
||||||
.catch(error => { |
|
||||||
throw `${error.stack} \n\n Message : Epub parsing failed.`; |
|
||||||
}); |
|
||||||
}, [book]); |
|
||||||
/* eslint-enable */ |
|
||||||
|
|
||||||
/** Set viewer Styles/Options */ |
|
||||||
useEffect(() => { |
|
||||||
viewerStyle && setBookStyle(viewerStyle); |
|
||||||
viewerOption && setBookOption(viewerOption); |
|
||||||
}, [viewerStyle, viewerOption]); |
|
||||||
|
|
||||||
/** Apply viewer Styles/Options */ |
|
||||||
useEffect(() => { |
|
||||||
if (!rendition) return; |
|
||||||
|
|
||||||
onResize(); |
|
||||||
|
|
||||||
const newStyle = { |
|
||||||
"body": { |
|
||||||
"padding-top": "0px !important", |
|
||||||
"padding-bottom": "0px !important" |
|
||||||
}, |
|
||||||
"p": { |
|
||||||
"font-size": `${bookStyle.fontSize}px !important`, |
|
||||||
"line-height": `${bookStyle.lineHeight} !important` |
|
||||||
}, |
|
||||||
}; |
|
||||||
|
|
||||||
rendition.flow(bookOption.flow); |
|
||||||
rendition.spread(bookOption.spread); |
|
||||||
|
|
||||||
if (bookStyle.fontFamily !== "Origin") { |
|
||||||
Object.assign(newStyle.body, { |
|
||||||
"font-family": `${bookStyle.fontFamily} !important` |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
if (bookOption.flow === "scrolled-doc") { // Scroll type
|
|
||||||
Object.assign(newStyle.body, { |
|
||||||
"margin": "auto !important" |
|
||||||
}); |
|
||||||
} else if (bookOption.spread === "auto") { // View 2 pages
|
|
||||||
Object.assign(newStyle.body, { }); |
|
||||||
} else { // View 1 page
|
|
||||||
Object.assign(newStyle.body, { }); |
|
||||||
} |
|
||||||
|
|
||||||
rendition.themes.register("main", viewerDefaultStyles); |
|
||||||
rendition.themes.register("default", newStyle); |
|
||||||
|
|
||||||
rendition.themes.select("main"); |
|
||||||
}, [ |
|
||||||
rendition,
|
|
||||||
bookStyle.fontFamily, |
|
||||||
bookStyle.fontSize, |
|
||||||
bookStyle.lineHeight, |
|
||||||
bookOption, |
|
||||||
onResize |
|
||||||
]); |
|
||||||
|
|
||||||
/** Emit screen resizing event */ |
|
||||||
useEffect(() => { |
|
||||||
window.addEventListener('resize', onResize); |
|
||||||
return () => window.removeEventListener('resize', onResize); |
|
||||||
}, [onResize]); |
|
||||||
|
|
||||||
/** Emit selection event */ |
|
||||||
useEffect(() => { |
|
||||||
if (!rendition) return; |
|
||||||
rendition.on("mouseup", onSelected); |
|
||||||
return () => rendition.off("mouseup", onSelected); |
|
||||||
}, [rendition, onSelected]); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (<> |
|
||||||
<EpubViewer
|
|
||||||
url={url}
|
|
||||||
style={layoutStyle} |
|
||||||
bookChanged={bookChanged}
|
|
||||||
rendtionChanged={rendtionChanged}
|
|
||||||
tocChanged={onTocChange}
|
|
||||||
pageChanged={onPageChange} |
|
||||||
selectionChanged={selectionChanged} |
|
||||||
loadingView={loadingView || <LoadingView />} |
|
||||||
ref={ref} |
|
||||||
/> |
|
||||||
</>); |
|
||||||
} |
|
||||||
|
|
||||||
export default React.forwardRef(ReactViewer) |
|
@ -1,16 +0,0 @@ |
|||||||
const viewerStyle = { |
|
||||||
"::selection": { |
|
||||||
"background-color": "#d4e9ff" |
|
||||||
}, |
|
||||||
|
|
||||||
"img": { |
|
||||||
"-webkit-touch-callout": "none", |
|
||||||
"-webkit-user-select": "none", |
|
||||||
"-khtml-user-select": "none", |
|
||||||
"-moz-user-select": "none", |
|
||||||
"-ms-user-select": "none", |
|
||||||
"user-select": "none" |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
export default viewerStyle |
|
Loading…
Reference in new issue