react-pdf-highlighter
react-pdf-highlighter copied to clipboard
Error: not a valid JSX element
I'm getting this error: not a valid JSX element.
(base) raphy@pc:~/ForgeRaphyTemplate$ yarn start
yarn run v1.22.18
$ electron-forge start
✔ Checking your system
✔ Locating Application
✔ Preparing native dependencies: 4 / 4
✔ Compiling Main Process Code
✔ Launch Dev Servers
⠏ Compiling Preload ScriptsIssues checking in progress...
⠹ Compiling Preload ScriptsERROR in src/app_webpdf/components/App_webpdf.tsx:198:10
TS2786: 'PdfLoader' cannot be used as a JSX component.
Its instance type 'PdfLoader' is not a valid JSX element.
Types of property 'refs' are incompatible.
Type '{ [key: string]: import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").ReactInstance; }' is not assignable to type '{ [key: string]: React.ReactInstance; }'.
'string' index signatures are incompatible.
Type 'import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").ReactInstance' is not assignable to type 'React.ReactInstance'.
Type 'Component<any, {}, any>' is not assignable to type 'ReactInstance'.
Type 'import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").Component<any, {}, any>' is not assignable to type 'React.Component<any, {}, any>'.
The types returned by 'render()' are incompatible between these types.
Type 'import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").ReactNode' is not assignable to type 'React.ReactNode'.
Type '{}' is not assignable to type 'ReactNode'.
Type '{}' is missing the following properties from type 'ReactPortal': key, children, type, props
196 | >
197 |
> 198 | <PdfLoader url={url} beforeLoad={<Spinner />}>
| ^^^^^^^^^
199 | {(pdfDocument) => (
200 | <PdfHighlighter
201 | pdfDocument={pdfDocument}
ERROR in src/app_webpdf/components/App_webpdf.tsx:200:14
TS2786: 'PdfHighlighter' cannot be used as a JSX component.
Its instance type 'PdfHighlighter<IHighlight>' is not a valid JSX element.
Types of property 'refs' are incompatible.
Type '{ [key: string]: import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").ReactInstance; }' is not assignable to type '{ [key: string]: React.ReactInstance; }'.
'string' index signatures are incompatible.
Type 'import("/home/raphy/ForgeRaphyTemplate/node_modules/react-pdf-highlighter/node_modules/@types/react/index").ReactInstance' is not assignable to type 'React.ReactInstance'.
198 | <PdfLoader url={url} beforeLoad={<Spinner />}>
199 | {(pdfDocument) => (
> 200 | <PdfHighlighter
| ^^^^^^^^^^^^^^
201 | pdfDocument={pdfDocument}
202 | enableAreaSelection={(event) => event.altKey}
203 | onScrollChange={resetHash}
This is the complete App_webpdf.tsx
file :
import * as React from 'react';
import {
PdfLoader,
PdfHighlighter,
Tip,
Highlight,
Popup,
AreaHighlight,
} from "react-pdf-highlighter";
import type { IHighlight, NewHighlight } from "react-pdf-highlighter";
import { testHighlights as _testHighlights } from "./pdf_highlight/test-highlights";
import { Spinner } from "./pdf_highlight/Spinner";
import { Sidebar } from "./pdf_highlight/Sidebar";
const testHighlights: Record<string, Array<IHighlight>> = _testHighlights
const HighlightPopup = ({
comment,
}: {
comment: { text: string; emoji: string };
}) =>
comment.text ? (
<div className="Highlight__popup">
{comment.emoji} {comment.text}
</div>
) : null
interface State {
url: string;
highlights: Array<IHighlight>;
}
const parseIdFromHash = () =>
document.location.hash.slice("#highlight-".length)
const resetHash = () => {
document.location.hash = ""
}
const getNextId = () =>
String(Math.random()).slice(2)
// https://nimblewebdeveloper.com/blog/convert-react-class-to-function-component
//const SECONDARY_PDF_URL = "https://arxiv.org/pdf/1604.02480.pdf"
const SECONDARY_PDF_URL = ""
function App_webpdf() {
const componentIsMounted = React.useRef(true)
React.useEffect(() => {
const cb = (event, args) => {
try {
if (componentIsMounted.current) {
console.log("args: ", args)
}
} catch (err) {
console.log("err: ", err)
}
}
// @ts-ignore
window.api.electronIpcOn("window-webpdf-opened", cb)
// @ts-ignore
window.api.electronIpcSend("from-window-webpdf", "This is the WindowWebpdf");
window.api.electronIpcSend("webpdf-available","");
return () => { // clean-up function
componentIsMounted.current = false
window.api.electronIpcRemoveListener(
"webpdf-channel",
cb,
)
}
}, [])
const [initialurl, setInitialurl] = React.useState("")
const [state, setState] = React.useState({
url: "",
highlights: testHighlights[initialurl]
? [...testHighlights[initialurl]]
: [],
})
React.useEffect(() => {
// @ts-ignore
window.api.electronIpcOn("window-webpdf-channel-from-main", (event, args) => {
console.log("App_webpdf-window-webpdf-channel-from-main-args: ", args)
setInitialurl(args);
});
return () => { // clean-up function
}
}, [])
console.log("url-updated: ", initialurl)
const resetHighlights = () => {
setState({
url: initialurl,
highlights: []
})
}
const toggleDocument = () => {
const newUrl =
state.url === initialurl ? SECONDARY_PDF_URL : initialurl
setState({
url: newUrl,
highlights: testHighlights[newUrl] ? [...testHighlights[newUrl]] : [],
})
}
let scrollViewerTo = (highlight: any) => {}
const getHighlightById = (id: string) => {
const { highlights } = state
return highlights.find((highlight) => highlight.id === id)
}
const scrollToHighlightFromHash = () => {
const highlight = getHighlightById(parseIdFromHash())
if (highlight) {
scrollViewerTo(highlight)
}
}
const addHighlight = (highlight: NewHighlight) => {
const { highlights } = state
console.log("Saving highlight", highlight)
setState({
url: initialurl,
highlights: [{ ...highlight, id: getNextId() }, ...highlights],
})
}
const updateHighlight = (highlightId: string, position: Object, content: Object) => {
console.log("Updating highlight: ", highlightId, position, content)
setState({
url: initialurl,
highlights: state.highlights.map((h) => {
const {
id,
position: originalPosition,
content: originalContent,
...rest
} = h
return id === highlightId
? {
id,
position: { ...originalPosition, ...position },
content: { ...originalContent, ...content },
...rest,
}
: h;
})
})
}
const { url, highlights } = state
return (
<div className='container' style={{ display: "flex", height: "100vh" }}>
<Sidebar
highlights={highlights}
resetHighlights={resetHighlights}
toggleDocument={toggleDocument}
/>
<div
style={{
height: "100vh",
width: "75vw",
position: "relative",
}}
>
<PdfLoader url={url} beforeLoad={<Spinner />}>
{(pdfDocument) => (
<PdfHighlighter
pdfDocument={pdfDocument}
enableAreaSelection={(event) => event.altKey}
onScrollChange={resetHash}
// pdfScaleValue="page-width"
scrollRef={(scrollTo) => {
// @ts-ignore
scrollViewerTo = scrollTo
scrollToHighlightFromHash()
}}
onSelectionFinished={(
position,
content,
hideTipAndSelection,
transformSelection
) => (
<Tip
onOpen={transformSelection}
onConfirm={(comment) => {
addHighlight({ content, position, comment })
hideTipAndSelection()
}}
/>
)}
highlightTransform={(
highlight,
index,
setTip,
hideTip,
viewportToScaled,
screenshot,
isScrolledTo
) => {
const isTextHighlight = !Boolean(
highlight.content && highlight.content.image
)
const component = isTextHighlight ? (
<Highlight
isScrolledTo={isScrolledTo}
position={highlight.position}
comment={highlight.comment}
/>
) : (
<AreaHighlight
isScrolledTo={isScrolledTo}
highlight={highlight}
onChange={(boundingRect) => {
updateHighlight(
highlight.id,
{ boundingRect: viewportToScaled(boundingRect) },
{ image: screenshot(boundingRect) }
)
}}
/>
)
return (
<Popup
popupContent={<HighlightPopup {...highlight} />}
onMouseOver={(popupContent) =>
setTip(highlight, (highlight) => popupContent)
}
onMouseOut={hideTip}
key={index}
children={component}
/>
)
}}
highlights={highlights}
/>
)}
</PdfLoader>
</div>
</div>
);
}
export default App_webpdf;
Complete webpack configuration
:
webpack.renderer.config.js
:
const rules = require('./webpack.rules');
const plugins = require('./webpack.plugins');
rules.push({
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
});
module.exports = {
module: {
rules,
},
plugins: plugins,
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
// https://stackoverflow.com/questions/67348426/how-fix-breaking-change-webpack-5-used-to-include-polyfills-for-node-js-core
fallback: {
fs: false,
'stream': require.resolve('stream-browserify'),
'buffer': require.resolve('buffer/'),
'util': require.resolve('util/'),
'assert': require.resolve('assert/'),
'http': require.resolve('stream-http/'),
'url': require.resolve('url/'),
'https': require.resolve('https-browserify/'),
'os': require.resolve('os-browserify/'),
},
},
};
webpack.main.config.js
:
module.exports = {
/**
* This is the main entry point for your application, it's the first file
* that runs in the main process.
*/
//entry: [
//'./src/main/index.ts',
//],
entry: './src/main/index.ts',
// Put your normal webpack config below here
module: {
rules: require('./webpack.rules'),
},
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css', '.json'],
// https://stackoverflow.com/questions/67348426/how-fix-breaking-change-webpack-5-used-to-include-polyfills-for-node-js-core
fallback: {
fs: false,
'stream': require.resolve('stream-browserify'),
'buffer': require.resolve('buffer/'),
'util': require.resolve('util/'),
'assert': require.resolve('assert/'),
'http': require.resolve('stream-http/'),
'url': require.resolve('url/'),
'https': require.resolve('https-browserify/'),
'os': require.resolve('os-browserify/'),
},
},
};
webpack.plugins.js
:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin")
const path = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = [
new ForkTsCheckerWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/app/index.html',
inject:'body',
chunks: ['app'],
}),
// https://github.com/webpack-contrib/mini-css-extract-plugin#recommended
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: "[name].css",
chunkFilename: "[id].css",
linkType: 'text/css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "./src/assets/epub"),
to: path.resolve(__dirname, ".webpack/assets/epub")
},
{
from: path.resolve(__dirname, "./src/assets/svg"),
to: path.resolve(__dirname, ".webpack/assets/svg")
},
{
from: path.resolve(__dirname, "./src/assets/geojson"),
to: path.resolve(__dirname, ".webpack/assets/geojson")
},
{
from: path.resolve(__dirname, "./src/assets/pics"),
to: path.resolve(__dirname, ".webpack/assets/pics")
},
{
from: path.resolve(__dirname, "./src/assets/css"),
to: path.resolve(__dirname, ".webpack/assets/css")
},
{
from: path.resolve(__dirname, "./node_modules/onnxruntime-web/dist/*.wasm"),
to: path.resolve(__dirname, "[name][ext]")
},
{
from: path.resolve(__dirname, "./src/assets/onnx-models"),
to: path.resolve(__dirname, ".webpackassets/onnx-models")
}
]
})
];
webpack.rules.js
:
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = [
// Add support for native node modules
{
// We're specifying native_modules in the test because the asset relocator loader generates a
// "fake" .node file which is really a cjs file.
test: /native_modules\/.+\.node$/,
use: 'node-loader',
},
{
test: /\.(m?js|node)$/,
parser: { amd: false },
use: {
loader: '@vercel/webpack-asset-relocator-loader',
options: {
outputAssetBase: 'native_modules',
},
},
},
{
test: /\.(js|ts)x?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/react', {
'plugins': ['@babel/plugin-proposal-class-properties']}
]
}
},
},
{
test: /\.tsx?$/,
exclude: /(node_modules|\.webpack)/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
},
{
test: /\.(svg)$/i,
type: 'asset',
generator: {
outputPath: '.webpack/assets/svg/'
},
},
{
test: /\.(png|jpe?g|gif)$/i,
type: 'asset',
generator: {
outputPath: '.webpack/assets/pics/'
},
},
{
// Font files
test: /\.(woff|woff2|ttf|otf)$/,
type: 'asset',
generator: {
outputPath: '.wepack/assets/css/'
},
},
{
test: /\.ts$/,
include: /src/,
use: [{ loader: 'ts-loader' }]
},
// https://github.com/webpack-contrib/mini-css-extract-plugin#getting-started
{
test: /\.(sass|less|css)$/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "style-loader"],
generator: {
outputPath: '.webpack/assets/css/'
},
},
{
test: /\.pcss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{ // https://github.com/webpack-contrib/postcss-loader#getting-started
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
"postcss-preset-env",
],
},
//sourceMap: true,
},
},
],
}
];
Other info:
node: v16.15.0
O.S. : Ubuntu 20.04 Desktop
"webpack": "^5.73.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.2"
How to solve the problem? How to make it work?
What version of react are you using?
This should resolve https://github.com/agentcooper/react-pdf-highlighter/pull/195
@milesangelo Your PR appears to be in error. Would you fix it?
https://github.com/agentcooper/react-pdf-highlighter/runs/7152693658?check_suite_focus=true
Hi! Could anybody share any updates on this issue? Thanks
It looks like the problem appears to be the packaged version of the library is somehow deployed using relative paths and once it ends up in my node_modules it fails to load various of its own dependencies
It is attempting to load "PdfLoader.tsx" from "http://localhost:3000/Users/
Could not load content for http://localhost:3000/Users/<user>/src/components/PdfLoader.tsx (HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE)

As a work around I just pulled in all the source files locally into my project
Hi! Still getting this same issue, any way to work around it or some ETA for React 18?