Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,6 @@ __TEST__
/playwright/.cache/
/e2e-report/
_examples

# specs
specs/
36 changes: 31 additions & 5 deletions examples/content-preact/content/scripts.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {render} from 'preact'
import ContentApp from './ContentApp'
import './styles.css?inline_style'

let unmount: () => void
import.meta.webpackHot?.accept()
import.meta.webpackHot?.dispose(() => unmount?.())

if (document.readyState === 'complete') {
initial()
unmount = initial() || (() => {})
} else {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') initial()
if (document.readyState === 'complete') unmount = initial() || (() => {})
})
}

Expand All @@ -21,13 +24,36 @@ function initial() {
// This way, styles from the extension won't leak into the host page.
const shadowRoot = rootDiv.attachShadow({mode: 'open'})

// Inform Extension.js that the shadow root is available.
window.__EXTENSION_SHADOW_ROOT__ = shadowRoot
const style = document.createElement('style')
shadowRoot.appendChild(style)

fetchCSS().then((response) => {
style.textContent = response
})
console.log('Running....???')

import.meta.webpackHot?.accept('./styles.css', () => {
fetchCSS().then((response) => {
style.textContent = response
})
})

// Preact specific rendering
render(
<div className="content_script">
<ContentApp />
</div>,
shadowRoot
)

return () => {
// Preact's render returns undefined, so we just remove the root
rootDiv.remove()
}
}

async function fetchCSS() {
const response = await fetch(new URL('./styles.css', import.meta.url))
const text = await response.text()
return response.ok ? text : Promise.reject(text)
}
44 changes: 37 additions & 7 deletions examples/content-react/content/scripts.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import ReactDOM from 'react-dom/client'
import ContentApp from './ContentApp'
import './styles.css?inline_style'

let unmount: () => void
// @ts-expect-error - global reference.
import.meta.webpackHot?.accept()
// @ts-expect-error - global reference.
import.meta.webpackHot?.dispose(() => unmount?.())

if (document.readyState === 'complete') {
initial()
unmount = initial() || (() => {})
} else {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') initial()
if (document.readyState === 'complete') unmount = initial() || (() => {})
})
}

console.log('Extension running...')

function initial() {
// Create a new div element and append it to the document's body
const rootDiv = document.createElement('div')
Expand All @@ -21,13 +28,36 @@ function initial() {
// This way, styles from the extension won't leak into the host page.
const shadowRoot = rootDiv.attachShadow({mode: 'open'})

// Use the shadow root as the root element to inject styles into.
window.__EXTENSION_SHADOW_ROOT__ = shadowRoot
const style = document.createElement('style')
shadowRoot.appendChild(style)

fetchCSS().then((response) => {
style.textContent = response
})

// This needs to be inside initial() since it references the style element
// that is created and used within this function's scope
// @ts-expect-error - global reference.
import.meta.webpackHot?.accept('./styles.css', () => {
fetchCSS().then((response) => {
style.textContent = response
})
})

const root = ReactDOM.createRoot(shadowRoot)
root.render(
const mountingPoint = ReactDOM.createRoot(shadowRoot)
mountingPoint.render(
<div className="content_script">
<ContentApp />
</div>
)
return () => {
mountingPoint.unmount()
rootDiv.remove()
}
}

async function fetchCSS() {
const response = await fetch(new URL('./styles.css', import.meta.url))
const text = await response.text()
return response.ok ? text : Promise.reject(text)
}
76 changes: 53 additions & 23 deletions examples/content-sass/content/scripts.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import './styles.scss?inline_style'
import logo from '../images/logo.svg'

console.log('hello from content_scripts')

let unmount
import.meta.webpackHot.accept()
import.meta.webpackHot.dispose(() => unmount())

if (document.readyState === 'complete') {
initial()
unmount = initial() || (() => {})
} else {
document.addEventListener('readystatechange', () => {
if (document.readyState === 'complete') initial()
if (document.readyState === 'complete') unmount = initial() || (() => {})
})
}

Expand All @@ -21,24 +24,51 @@ function initial() {
// This way, styles from the extension won't leak into the host page.
const shadowRoot = rootDiv.attachShadow({mode: 'open'})

// Inform Extension.js that the shadow root is available.
window.__EXTENSION_SHADOW_ROOT__ = shadowRoot

shadowRoot.innerHTML = `
<div class="content_script">
<img class="content_logo" src="${logo}" />
<h1 class="content_title">
Welcome to your Sass Extension
</h1>
<p class="content_description">
Learn more about creating cross-browser extensions at <a
className="underline hover:no-underline"
href="https://extension.js.org"
target="_blank"
>
https://extension.js.org
</a>
</p>
</div>
`
const style = document.createElement('style')
shadowRoot.appendChild(style)

// Create content container div
const contentDiv = document.createElement('div')
contentDiv.className = 'content_script'
shadowRoot.appendChild(contentDiv)

// Create logo image
const logoImg = document.createElement('img')
logoImg.className = 'content_logo'
logoImg.src = logo
contentDiv.appendChild(logoImg)

// Create title
const title = document.createElement('h1')
title.className = 'content_title'
title.textContent = 'Welcome to your Sass Extension'
contentDiv.appendChild(title)

// Create description
const description = document.createElement('p')
description.className = 'content_description'
description.innerHTML =
'Learn more about creating cross-browser extensions at <a class="underline hover:no-underline" href="https://extension.js.org" target="_blank">https://extension.js.org</a>'
contentDiv.appendChild(description)

// Handle CSS injection
fetchCSS().then((response) => {
style.textContent = response
})

import.meta.webpackHot?.accept('./styles.scss', () => {
fetchCSS().then((response) => {
style.textContent = response
})
})

return () => {
rootDiv.remove()
}
}

async function fetchCSS() {
const response = await fetch(new URL('./styles.scss', import.meta.url))
const text = await response.text()
return response.ok ? text : Promise.reject(text)
}
22 changes: 12 additions & 10 deletions examples/content-sass/content/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@
}

.content_title {
font-size: 1.85em;
font: {
size: 1.85em;
family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
weight: 700;
}
line-height: 1.1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
font-weight: 700;
margin: 0;
}

.content_description {
font-size: small;
margin: 0;
}

.content_description a {
text-decoration: none;
border-bottom: 2px solid #c9c9c9;
color: #e5e7eb;
margin: 0;
a {
text-decoration: none;
border-bottom: 2px solid #c9c9c9;
color: #e5e7eb;
margin: 0;
}
}
31 changes: 31 additions & 0 deletions examples/content-svelte/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules

# testing
coverage

# production
dist

# misc
.DS_Store

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# lock files
yarn.lock
package-lock.json

# debug files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# extension.js
extension-env.d.ts
1 change: 1 addition & 0 deletions examples/content-svelte/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello from the background script!')
84 changes: 84 additions & 0 deletions examples/content-svelte/content/ContentApp.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script lang="ts">
import svelteLogo from '../images/svelte.png'
import tailwindBg from '../images/tailwind_bg.png'
import typescriptLogo from '../images/typescript.png'
import tailwindLogo from '../images/tailwind.png'
import chromeWindowBg from '../images/chromeWindow.png'

let isDialogOpen = true

function toggleDialog() {
isDialogOpen = !isDialogOpen
}
</script>

{#if !isDialogOpen}
<div class="mx-auto p-6">
<button
on:click={toggleDialog}
class="bg-white rounded-md p-3 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
>
🧩 Open content script hint <span aria-hidden="true">+</span>
</button>
</div>
{:else}
<div class="mx-auto max-w-7xl md:px-0 lg:p-6">
<div class="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl lg:rounded-3xl md:pt-24 md:h-full sm:h-[100vh] lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
<div class="absolute z-20 top-0 inset-x-0 flex justify-center overflow-hidden pointer-events-none">
<div class="w-[108rem] flex-none flex justify-end">
<picture>
<img
src={tailwindBg}
alt=""
class="w-[90rem] flex-none max-w-none hidden dark:block"
decoding="async"
/>
</picture>
</div>
</div>
<div class="mx-auto max-w-md text-center lg:py-12 lg:mx-0 lg:flex-auto lg:text-left">
<div class="flex items-center justify-center space-x-4 my-4 mx-auto">
<img
alt="React logo"
src={svelteLogo}
class="relative inline-block w-12"
/>
<div class="text-3xl text-white">+</div>
<img
alt="TypeScript logo"
src={typescriptLogo}
class="relative inline-block w-12"
/>
<div class="text-3xl text-white">+</div>
<img
alt="Tailwind logo"
src={tailwindLogo}
class="relative inline-block w-12"
/>
</div>
<h2 class="text-3xl font-bold tracking-tight text-white sm:text-4xl">
This is a content script running Svelte, TypeScript, and Tailwind.css
</h2>
<p class="mt-6 text-lg leading-8 text-gray-300">
Learn more about creating cross-browser extensions by
<button
on:click={toggleDialog}
class="underline hover:no-underline"
>
closing this hint
</button>
.
</p>
</div>
<div class="relative mt-16 h-80 lg:mt-8">
<img
class="absolute left-0 top-0 w-[57rem] max-w-none rounded-md bg-white/5 ring-1 ring-white/10"
src={chromeWindowBg}
alt="Chrome window screenshot"
width="1824"
height="1080"
/>
</div>
</div>
</div>
{/if}
Loading