lxieyang / chrome-extension-boilerplate-react

A Chrome Extensions boilerplate using React 18 and Webpack 5.
MIT License
3.57k stars 1.1k forks source link

How to import a jsx react in content script #119

Closed moshOntong-IT closed 2 years ago

moshOntong-IT commented 2 years ago

So I was planning to create a popover when the user select some text in web content.

Before I manually coded like this const popWrapper = document.createElement("div"); popWrapper.id = "kit-translator-button"; const popIcon = document.createElement("div"); popIcon.classList.add("kit-pop-icon"); popIcon.innerHTML =<svg version="1.1" id="anna_vital_language_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="15px" height="15px" fill="#ffff" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve"> `;

//TODO add css in manifestation to make this readable;

const popWrapperText = document.createElement("SPAN");
popWrapperText.innerText = "Kitkat Translate";
popWrapperText.style.color = "white";
popWrapper.style.fontSize = "14px";

popWrapper.appendChild(popIcon);
popWrapper.appendChild(popWrapperText);

const top =
  selectBoundingClientRect.top + selectBoundingClientRect.height + 6 + "px";
const left =
  selectBoundingClientRect.left +
  (selectBoundingClientRect.width / 2 - popWrapper.offsetWidth / 2) +
  "px";

// console.log(top + " " + left);
popWrapper.style.position = "absolute";
popWrapper.style.display = "flex";
popWrapper.style.justifyContent = "space-around";
popWrapper.style.alignContent = "center";
popWrapper.style.background = "black";
popWrapper.style.width = "150px";
popWrapper.style.padding = "4px";
popWrapper.style.top = top;
popWrapper.style.left = left;
popWrapper.style.cursor = "pointer";

this.bodyDOM.appendChild(popWrapper);

if (popWrapper) {
  popWrapper.addEventListener("click", () => {
    if (selectedText.length > 0) {
      const value = selectionTextRange.toString();
      let selectedElement = document.createElement("SPAN");
      selectedElement.className = "kit-node";

      selectedElement.attachShadow({ mode: "open" });

      // selectedElement.style.backgroundColor = "red";
      // selectedElement.style.fontWeight = "bold";

      let shadowHeader = document.createElement("SPAN");
      shadowHeader.className = "kit-header";

      //TODO optimize css
      let shadowBody = document.createElement("SPAN");
      shadowBody.className = "kit-body";
      shadowBody.style.display = "inline-block";
      shadowBody.style.background = "red";
      shadowBody.innerText = value;

      selectedElement.shadowRoot.appendChild(shadowHeader);
      selectedElement.shadowRoot.appendChild(shadowBody);

      selectionTextRange.deleteContents();
      selectionTextRange.insertNode(selectedElement);

      this.removePopWrapper();
    }
  });
}

`

As you can see this is not kinda readable thing in our eyes, right. I want to render this element by using the react-dom.

DovahBrownies commented 2 years ago

If I'm understanding your correctly, you want to render a custom React component on a webpage of your choice. All you need to do is use ReactDOM.render. Here's a full example (not tested):

Create your React component:

MyComponent.js

import React from 'react';

const MyComponent = () => <div>This is my component</div>

export default MyComponent

Then in your Content script file, you need to (1) import the component, (2) create or find an element on the webpage to manipulate, and (3) render your React component in that element:

Content/index.js

// (1) Import component
import MyComponent from '..../MyComponent';

...

// (2) Create `myElement` to manipulate
const myElement = document.createElement('div');
myElement.setAttribute('id', 'MY-COMPONENT-ID');
myElement.setAttribute('style', 'all:unset');

// (2) Find an element in the DOM to manipulate
const foundExistingElement = document.querySelector('SOME-EXISTING-ELEMENT-HERE');

// (2) Here we're injecting `myElement` into the found existing element on the page. (Alternatively we can manipulate the existing element directly - Explained below on (4))
foundExistingElement.prepend(myElement)

// (3) Render your React component inside the `myElement` that you injected into the webpage in step (2).
ReactDOM.render(
  <MyComponent />,
  // (4) Alternatively, you can just target an existing element on the page here without needing to create `myElement`.
  document.getElementById('MY-COMPONENT-ID')
);

The above should render <MyComponent /> on your webpage on every successful load (Given that you target the correct elements).

Now you can add custom events and listeners to make it render on command.

Hope this helps!

moshOntong-IT commented 2 years ago

Thank you so much

J-Filip commented 2 years ago

I think this should be added in the documentation or added to the content script example code.