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