react-reader
Advanced tools
Comparing version
@@ -33,3 +33,3 @@ import { default as React, Component } from 'react'; | ||
state: Readonly<IEpubViewState>; | ||
viewerRef: React.RefObject<HTMLDivElement>; | ||
viewerRef: React.RefObject<HTMLDivElement | null>; | ||
location?: string | number | null; | ||
@@ -36,0 +36,0 @@ book?: Book; |
@@ -346,2 +346,104 @@ var __defProp = Object.defineProperty; | ||
}); | ||
// Changing Page based on direction of scroll | ||
__publicField(this, "handleWheel", (event) => { | ||
var _a, _b; | ||
event.preventDefault(); | ||
const node = this.readerRef.current; | ||
if (!node) return; | ||
if (event.deltaY > 0) { | ||
(_a = node.nextPage) == null ? void 0 : _a.call(node); | ||
} else if (event.deltaY < 0) { | ||
(_b = node.prevPage) == null ? void 0 : _b.call(node); | ||
} | ||
}); | ||
// Setting up event listener in the iframe of the viewer | ||
__publicField(this, "attachWheelListener", () => { | ||
if (!this.readerRef.current) return; | ||
const rendition = this.readerRef.current.rendition; | ||
if (rendition) { | ||
rendition.hooks.content.register( | ||
(contents) => { | ||
const iframeDoc = contents.window.document; | ||
iframeDoc.removeEventListener("wheel", this.handleWheel); | ||
iframeDoc.addEventListener("wheel", this.handleWheel, { | ||
passive: false | ||
}); | ||
} | ||
); | ||
} | ||
}); | ||
//search function to find all occurence and set amount of charecters for context | ||
__publicField(this, "searchInBook", async (query) => { | ||
var _a, _b, _c, _d, _e; | ||
if (!this.readerRef.current) return; | ||
const rendition = (_a = this.readerRef.current) == null ? void 0 : _a.rendition; | ||
const book = rendition == null ? void 0 : rendition.book; | ||
if (!book) return; | ||
if (!query) { | ||
(_c = (_b = this.props).onSearchResults) == null ? void 0 : _c.call(_b, []); | ||
return; | ||
} | ||
await book.ready; | ||
const results = []; | ||
const promises = []; | ||
book.spine.each((item) => { | ||
const promise = (async () => { | ||
try { | ||
await item.load(book.load.bind(book)); | ||
const doc = item.document; | ||
const textNodes = []; | ||
const treeWalker = doc.createTreeWalker( | ||
doc, | ||
NodeFilter.SHOW_TEXT, | ||
null, | ||
false | ||
); | ||
let node; | ||
while (node = treeWalker.nextNode()) { | ||
textNodes.push(node); | ||
} | ||
const fullText = textNodes.map((n) => n.textContent).join("").toLowerCase(); | ||
const searchQuery = query.toLowerCase(); | ||
let pos = fullText.indexOf(searchQuery); | ||
while (pos !== -1) { | ||
let nodeIndex = 0; | ||
let foundOffset = pos; | ||
while (nodeIndex < textNodes.length) { | ||
const nodeText = textNodes[nodeIndex].textContent || ""; | ||
if (foundOffset < nodeText.length) break; | ||
foundOffset -= nodeText.length; | ||
nodeIndex++; | ||
} | ||
if (nodeIndex < textNodes.length) { | ||
let range = doc.createRange(); | ||
try { | ||
range.setStart(textNodes[nodeIndex], foundOffset); | ||
range.setEnd( | ||
textNodes[nodeIndex], | ||
foundOffset + searchQuery.length | ||
); | ||
const cfi = item.cfiFromRange(range); | ||
const excerpt = `${fullText.substring( | ||
Math.max(0, pos - (this.props.contextLength || 15)), | ||
pos + searchQuery.length + (this.props.contextLength || 15) | ||
)}`; | ||
results.push({ cfi, excerpt }); | ||
} catch (e) { | ||
console.warn("Skipping invalid range:", e); | ||
} | ||
} | ||
pos = fullText.indexOf(searchQuery, pos + 1); | ||
} | ||
item.unload(); | ||
} catch (error) { | ||
console.error("Error searching chapter:", error); | ||
} | ||
})(); | ||
promises.push(promise); | ||
}); | ||
await Promise.all(promises); | ||
if (query == this.props.searchQuery) { | ||
(_e = (_d = this.props).onSearchResults) == null ? void 0 : _e.call(_d, results); | ||
} | ||
}); | ||
} | ||
@@ -401,2 +503,11 @@ renderToc() { | ||
} | ||
//Actions to perform when the component updates | ||
componentDidUpdate(prevProps) { | ||
if (prevProps.searchQuery !== this.props.searchQuery) { | ||
this.searchInBook(this.props.searchQuery); | ||
} | ||
if (this.props.pageTurnOnScroll === true) { | ||
this.attachWheelListener(); | ||
} | ||
} | ||
render() { | ||
@@ -412,2 +523,5 @@ const { | ||
isRTL = false, | ||
pageTurnOnScroll = false, | ||
searchQuery, | ||
contextLength, | ||
...props | ||
@@ -414,0 +528,0 @@ } = this.props; |
@@ -346,2 +346,104 @@ (function(global, factory) { | ||
}); | ||
// Changing Page based on direction of scroll | ||
__publicField(this, "handleWheel", (event) => { | ||
var _a, _b; | ||
event.preventDefault(); | ||
const node = this.readerRef.current; | ||
if (!node) return; | ||
if (event.deltaY > 0) { | ||
(_a = node.nextPage) == null ? void 0 : _a.call(node); | ||
} else if (event.deltaY < 0) { | ||
(_b = node.prevPage) == null ? void 0 : _b.call(node); | ||
} | ||
}); | ||
// Setting up event listener in the iframe of the viewer | ||
__publicField(this, "attachWheelListener", () => { | ||
if (!this.readerRef.current) return; | ||
const rendition = this.readerRef.current.rendition; | ||
if (rendition) { | ||
rendition.hooks.content.register( | ||
(contents) => { | ||
const iframeDoc = contents.window.document; | ||
iframeDoc.removeEventListener("wheel", this.handleWheel); | ||
iframeDoc.addEventListener("wheel", this.handleWheel, { | ||
passive: false | ||
}); | ||
} | ||
); | ||
} | ||
}); | ||
//search function to find all occurence and set amount of charecters for context | ||
__publicField(this, "searchInBook", async (query) => { | ||
var _a, _b, _c, _d, _e; | ||
if (!this.readerRef.current) return; | ||
const rendition = (_a = this.readerRef.current) == null ? void 0 : _a.rendition; | ||
const book = rendition == null ? void 0 : rendition.book; | ||
if (!book) return; | ||
if (!query) { | ||
(_c = (_b = this.props).onSearchResults) == null ? void 0 : _c.call(_b, []); | ||
return; | ||
} | ||
await book.ready; | ||
const results = []; | ||
const promises = []; | ||
book.spine.each((item) => { | ||
const promise = (async () => { | ||
try { | ||
await item.load(book.load.bind(book)); | ||
const doc = item.document; | ||
const textNodes = []; | ||
const treeWalker = doc.createTreeWalker( | ||
doc, | ||
NodeFilter.SHOW_TEXT, | ||
null, | ||
false | ||
); | ||
let node; | ||
while (node = treeWalker.nextNode()) { | ||
textNodes.push(node); | ||
} | ||
const fullText = textNodes.map((n) => n.textContent).join("").toLowerCase(); | ||
const searchQuery = query.toLowerCase(); | ||
let pos = fullText.indexOf(searchQuery); | ||
while (pos !== -1) { | ||
let nodeIndex = 0; | ||
let foundOffset = pos; | ||
while (nodeIndex < textNodes.length) { | ||
const nodeText = textNodes[nodeIndex].textContent || ""; | ||
if (foundOffset < nodeText.length) break; | ||
foundOffset -= nodeText.length; | ||
nodeIndex++; | ||
} | ||
if (nodeIndex < textNodes.length) { | ||
let range = doc.createRange(); | ||
try { | ||
range.setStart(textNodes[nodeIndex], foundOffset); | ||
range.setEnd( | ||
textNodes[nodeIndex], | ||
foundOffset + searchQuery.length | ||
); | ||
const cfi = item.cfiFromRange(range); | ||
const excerpt = `${fullText.substring( | ||
Math.max(0, pos - (this.props.contextLength || 15)), | ||
pos + searchQuery.length + (this.props.contextLength || 15) | ||
)}`; | ||
results.push({ cfi, excerpt }); | ||
} catch (e) { | ||
console.warn("Skipping invalid range:", e); | ||
} | ||
} | ||
pos = fullText.indexOf(searchQuery, pos + 1); | ||
} | ||
item.unload(); | ||
} catch (error) { | ||
console.error("Error searching chapter:", error); | ||
} | ||
})(); | ||
promises.push(promise); | ||
}); | ||
await Promise.all(promises); | ||
if (query == this.props.searchQuery) { | ||
(_e = (_d = this.props).onSearchResults) == null ? void 0 : _e.call(_d, results); | ||
} | ||
}); | ||
} | ||
@@ -401,2 +503,11 @@ renderToc() { | ||
} | ||
//Actions to perform when the component updates | ||
componentDidUpdate(prevProps) { | ||
if (prevProps.searchQuery !== this.props.searchQuery) { | ||
this.searchInBook(this.props.searchQuery); | ||
} | ||
if (this.props.pageTurnOnScroll === true) { | ||
this.attachWheelListener(); | ||
} | ||
} | ||
render() { | ||
@@ -412,2 +523,5 @@ const { | ||
isRTL = false, | ||
pageTurnOnScroll = false, | ||
searchQuery, | ||
contextLength, | ||
...props | ||
@@ -414,0 +528,0 @@ } = this.props; |
@@ -12,3 +12,11 @@ import { default as React, PureComponent } from 'react'; | ||
isRTL?: boolean; | ||
pageTurnOnScroll?: boolean; | ||
searchQuery?: string; | ||
contextLength?: number; | ||
onSearchResults?: (results: SearchResult[]) => void; | ||
}; | ||
type SearchResult = { | ||
cfi: string; | ||
excerpt: string; | ||
}; | ||
type IReactReaderState = { | ||
@@ -21,3 +29,3 @@ isLoaded: boolean; | ||
state: Readonly<IReactReaderState>; | ||
readerRef: React.RefObject<EpubView>; | ||
readerRef: React.RefObject<EpubView | null>; | ||
constructor(props: IReactReaderProps); | ||
@@ -31,4 +39,8 @@ toggleToc: () => void; | ||
renderTocToggle(): import("react/jsx-runtime").JSX.Element; | ||
handleWheel: (event: WheelEvent) => void; | ||
attachWheelListener: () => void; | ||
searchInBook: (query?: string) => Promise<void>; | ||
componentDidUpdate(prevProps: IReactReaderProps): void; | ||
render(): import("react/jsx-runtime").JSX.Element; | ||
} | ||
export {}; |
{ | ||
"name": "react-reader", | ||
"version": "2.0.12", | ||
"version": "2.0.13", | ||
"description": "A epub-reader for React powered by ePubJS", | ||
@@ -55,25 +55,25 @@ "type": "module", | ||
"devDependencies": { | ||
"@tailwindcss/postcss": "^4.0.13", | ||
"@testing-library/jest-dom": "^6.6.3", | ||
"@testing-library/react": "^16.1.0", | ||
"@testing-library/react": "^16.2.0", | ||
"@types/jest": "^29.5.14", | ||
"@types/node": "^22.10.2", | ||
"@types/react": "^18.3.16", | ||
"@types/react-dom": "^18.3.5", | ||
"@types/node": "^22.13.10", | ||
"@types/react": "^19.0.10", | ||
"@types/react-dom": "^19.0.4", | ||
"@vitejs/plugin-react": "^4.3.4", | ||
"autoprefixer": "^10.4.20", | ||
"classnames": "^2.5.1", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"postcss": "^8.4.49", | ||
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"react-router-dom": "^6.28.0", | ||
"postcss": "^8.5.3", | ||
"react": "^19.0.0", | ||
"react-dom": "^19.0.0", | ||
"react-router-dom": "^7.3.0", | ||
"rimraf": "^6.0.1", | ||
"tailwindcss": "^3.4.16", | ||
"ts-jest": "^29.2.5", | ||
"typescript": "^5.7.2", | ||
"tailwindcss": "^4.0.13", | ||
"ts-jest": "^29.2.6", | ||
"typescript": "^5.8.2", | ||
"use-local-storage-state": "^19.5.0", | ||
"vite": "^5.4.11", | ||
"vite-plugin-dts": "^4.3.0" | ||
"vite": "^6.2.1", | ||
"vite-plugin-dts": "^4.5.3" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
126153
22.39%1333
21.96%