Implement a way to insert content script in the middle of a page [RFC]
mfissehaye opened this issue · 1 comments
How do you envision this feature/change to look/work like?
The framework should allow react developer to be able to insert React components in the middle of the page instead of just being able to create an overlay
What is the purpose of this change/feature? Why?
Sometimes I want to be able to add the content after a button or below a div to improve user experience.
(OPTIONAL) Example implementations
For example adding more context to a specific portion of the page in a facebook feed, add a component (UI styled with tailwind let's say) after every other post.
(OPTIONAL) Contribution
- I would like to contribute to this RFC via a PR
Verify canary release
- I verified that the issue exists in
plasmo
canary release
Code of Conduct
- I agree to follow this project's Code of Conduct
- I checked the current issues for duplicate problems.
Currently this feature is not supported in Plasmo, But you can achieve this functionality using Mutation Observer to observe the element and then add whatever you want before or after that element.
Here is an example of the code that uses Arrive.js (provides events to watch for DOM elements creation and removal) that helped me:
import cssText from "data-text:~/contents/style.css"
import type { PlasmoCSConfig, PlasmoGetShadowHostId } from "plasmo"
import "arrive"
import { useEffect } from "react"
import { createRoot } from "react-dom/client"
export const config: PlasmoCSConfig = {
matches: ["*://*.example.com/*"]
}
const HOST_ID = "engage-csui"
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
export const getStyle = () => {
const style = document.createElement("style")
style.textContent = cssText
return style
}
export default () => {
useEffect(() => {
const elementSelector = "#selected-element-selector"
// Wait for the element to be added to the DOM
document.arrive(elementSelector, function (element) {
const buttonContainer = document.createElement("div")
createRoot(buttonContainer).render(<>{/* <AnyReactComponent/> */}</>)
element.insertBefore(buttonContainer, element.firstChild)
})
return () => {
document.unbindArrive(elementSelector)
}
}, [])
return <>{/* Element you want to add as overlay */}</>
}
You also have to declare arrive in globals.d.ts
declare global {
interface Document {
arrive(
selector: string,
options: any,
callback: (element: Element) => void
): void
arrive(selector: string, callback: (element: Element) => void): void
unbindArrive(selector: string): void
}
}
export {}