wojtekmaj / react-pdf

Display PDFs in your React app as easily as if they were images.
https://projects.wojtekmaj.pl/react-pdf
MIT License
9.33k stars 879 forks source link

Is it possible to add text for PDF with form? #630

Closed Nilanth closed 4 years ago

Nilanth commented 4 years ago

I want to add some text in an existing PDF and find the position of the added text and need to replace the new text dynamically based in the position or add text?

wojtekmaj commented 4 years ago

I don't think so. Treat React-PDF as img tag for PDFs :)

YordanovDnA commented 4 years ago

Yes, it is possible with React. I can also share the project with you if you want.

index.js

import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap/dist/js/bootstrap";
import "popper.js/dist/popper";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { MyDocument } from "./components/firstPdf";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

App.js


import React from "react";
import { Link, Route } from "react-router-dom";
import Navigation from "./components/navigation";
import Files from "./components/files";
import "./App.css";

function App() {
  return (
    <div className="row vh-100">
      <nav className="navbar navbar-expand-lg navbar-light bg-light col-12 fixed-top">
        <Link className="navbar-brand" to="/#">
          Navbar
        </Link>
        <button
          className="navbar-toggler"
          type="button"
          data-toggle="collapse"
          data-target="#navbarText"
          aria-controls="navbarText"
          aria-expanded="false"
          aria-label="Toggle navigation"
        >
          <span className="navbar-toggler-icon" />
        </button>
        <div className="collapse navbar-collapse" id="navbarText">
          <ul className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link className="nav-link" to="/#">
                Home
              </Link>
            </li>
            <li className="nav-item">
              <Link className="nav-link" to="/#">
                Features
              </Link>
            </li>
            <li className="nav-item">
              <Link className="nav-link" to="/#">
                Pricing
              </Link>
            </li>
          </ul>
          <Link className="btn btn-outline-info my-2 my-sm-0" to="/login">
            Login
          </Link>
          <Link
            className="btn btn-outline-info my-2 my-sm-0 ml-3"
            to="/register"
          >
            Register
          </Link>
        </div>
      </nav>
      <div className="col-2 mt-5 shadow">
        <Navigation />
      </div>
      <div className="row col-10 mt-5 p-3">
        <Route path="/files" component={Files} />
      </div>
    </div>
  );
}

export default App;

navigation.jsx


import React, { Component } from "react";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faFile } from "@fortawesome/free-regular-svg-icons";

const styles = {
  navigation: {
    position: "fixed",
  },
};

class Navigation extends Component {
  state = {};

  render() {
    return (
      <React.Fragment>
        <div className="container mt-2" style={styles.navigation}>
          <FontAwesomeIcon icon={faFile} />
          <Link className="text-dark m-1" to="/files">
            New File
          </Link>
        </div>
      </React.Fragment>
    );
  }
}

export default Navigation;

files.jsx

import React, { Component } from "react";
import Pdf, { SaveBtn } from "./firstPdf";
import { pdf } from "@react-pdf/renderer";

class Files extends Component {
  state = {
    pdfText: {
      fileName: "",
      heading: "",
      text: "",
    },
  };

  updateState = (e) => {
    const pdfText = { ...this.state.pdfText };
    pdfText[e.currentTarget.name] = e.currentTarget.value;
    this.setState({ pdfText });
  };

  render() {
    const { heading, text, fileName } = this.state.pdfText;
    return (
      <React.Fragment>
        <form className="col-6">
          <form>
            <div className="form-group">
              <label htmlFor="name">File name:</label>
              <input
                name="fileName"
                onChange={this.updateState}
                type="text"
                className="form-control"
                id="name"
                placeholder="File name"
              />
            </div>
          </form>

          <div className="form-group">
            <label htmlFor="formGroupExampleInput">Heading:</label>
            <input
              name="heading"
              onChange={this.updateState}
              type="text"
              className="form-control"
              id="formGroupExampleInput"
              placeholder="Heading"
            />
          </div>
          <div className="form-group">
            <label htmlFor="formGroupExampleInput2">Text:</label>
            <textarea
              onChange={this.updateState}
              className="form-control"
              name="text"
              cols="30"
              rows="10"
            ></textarea>
          </div>
          <button className="btn btn-sm btn-primary">Save</button>
        </form>

        <div className="container col-6">
          <h3 className="text-center">Preview</h3>
          <Pdf heading={heading} text={text} fileName={fileName} />
        </div>
      </React.Fragment>
    );
  }
}

export default Files;

firstPdf.jsx

import React from "react";
import {
  Page,
  Text,
  View,
  Document,
  StyleSheet,
  PDFDownloadLink,
} from "@react-pdf/renderer";
import { PDFViewer } from "@react-pdf/renderer";
import url from "../imges/a.png";

// Create styles
const styles = StyleSheet.create({
  page: {
    flexDirection: "row",
    backgroundColor: "#E4E4E4",
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1,
  },
  heading: {
    fontSize: 26,
    textAlign: "center",
    marginBottom: 10,
  },
  text: {
    fontSize: 16,
  },
});

// Create Document Component
const MyDocument = ({ heading, text }) => {
  return (
    <Document title="Test">
      <Page size="A4" style={styles.page}>
        <View style={styles.section}>
          <Text style={styles.heading}>{heading}</Text>
          <Text>{text}</Text>
        </View>
      </Page>
    </Document>
  );
};

const Pdf = ({ heading, text, fileName }) => {
  console.log("Heading", heading);
  return (
    <React.Fragment>
      <PDFViewer width="100%" height="600px">
        <MyDocument heading={heading} text={text} />
      </PDFViewer>
      <PDFDownloadLink document={<MyDocument />} fileName={fileName}>
        {({ blob, url, loading, error }) =>
          loading ? (
            "Loading document..."
          ) : (
            <div className="d-flex justify-content-center">
              <button className="btn btn-sm btn-secondary">Download</button>
            </div>
          )
        }
      </PDFDownloadLink>
    </React.Fragment>
  );
};

export const SaveBtn = () => {
  return <div></div>;
};

export default Pdf;

package.json dependences:

"dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.30",
    "@fortawesome/free-brands-svg-icons": "^5.14.0",
    "@fortawesome/free-regular-svg-icons": "^5.14.0",
    "@fortawesome/free-solid-svg-icons": "^5.14.0",
    "@fortawesome/react-fontawesome": "^0.1.11",
    "@react-pdf/renderer": "^1.6.11",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "axios": "^0.20.0",
    "bootstrap": "^4.5.2",
    "joi-browser": "^13.4.0",
    "jquery": "^3.5.1",
    "lodash": "^4.17.20",
    "popper.js": "^1.16.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.3",
    "react-toastify": "^6.0.8"
  },