From c7940a0df08357cba3d8de1b8ebe35084725eff5 Mon Sep 17 00:00:00 2001
From: Andrea Cassani <32062066+andreacassani@users.noreply.github.com>
Date: Fri, 25 Nov 2022 14:34:54 +0100
Subject: [PATCH 1/4] Prevent Cloudflare Rocket Loader deferring script
---
src/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/index.tsx b/src/index.tsx
index f342956..a96f65e 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -262,7 +262,7 @@ const ThemeScript = memo(
)};}${fallbackColorScheme}}catch(t){}}();`
})()
- return
+ return
},
// Never re-render this component
() => true
From 2b4fc894ea514c7c1c942241cf2ba639aa6184e6 Mon Sep 17 00:00:00 2001
From: Andrea Cassani <32062066+andreacassani@users.noreply.github.com>
Date: Fri, 25 Nov 2022 20:14:49 +0100
Subject: [PATCH 2/4] Add scriptAttribute prop to ThemeProvider
---
README.md | 9 +++++++++
src/index.tsx | 11 +++++++----
src/types.ts | 6 ++++++
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 9bea936..d054391 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,7 @@ All your theme configuration is passed to ThemeProvider.
- `value`: Optional mapping of theme name to attribute value
- value is an `object` where key is the theme name and value is the attribute value ([example](#differing-dom-attribute-and-theme-name))
- `nonce`: Optional nonce passed to the injected `script` tag, used to allow-list the next-themes script in your CSP
+- `scriptAttribute`: Optional object used to pass custom pair of attributes and their values to the injected `script` ([example](#using-with-cloudflare-rocket-loader))
### useTheme
@@ -221,6 +222,14 @@ document.documentElement.getAttribute('data-theme')
// => "my-pink-theme"
```
+### Using with Cloudflare Rocket Loader
+
+[Rocket Loader](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/) is a Cloudflare optimization that defers the loading of inline and external scripts to prioritizes the website content. Since next-themes relies on a script injection to avoid screen flashing on page load, Rocket Loader breaks this functionality. Individual scripts [can be ignored](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/ignore-javascripts/) by adding the `data-cfasync="false"` attribute to the script tag:
+
+```js
+
+```
+
### More than light and dark mode
next-themes is designed to support any number of themes! Simply pass a list of themes:
diff --git a/src/index.tsx b/src/index.tsx
index a96f65e..f500a28 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -39,7 +39,8 @@ const Theme: React.FC = ({
attribute = 'data-theme',
value,
children,
- nonce
+ nonce,
+ scriptAttribute
}) => {
const [theme, setThemeState] = useState(() => getTheme(storageKey, defaultTheme))
const [resolvedTheme, setResolvedTheme] = useState(() => getTheme(storageKey))
@@ -164,7 +165,8 @@ const Theme: React.FC = ({
value,
children,
attrs,
- nonce
+ nonce,
+ scriptAttribute
}}
/>
{children}
@@ -182,7 +184,8 @@ const ThemeScript = memo(
defaultTheme,
value,
attrs,
- nonce
+ nonce,
+ scriptAttribute
}: ThemeProviderProps & { attrs: string[]; defaultTheme: string }) => {
const defaultSystem = defaultTheme === 'system'
@@ -262,7 +265,7 @@ const ThemeScript = memo(
)};}${fallbackColorScheme}}catch(t){}}();`
})()
- return
+ return
},
// Never re-render this component
() => true
diff --git a/src/types.ts b/src/types.ts
index d4e92ac..e54df4a 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,6 +2,10 @@ interface ValueObject {
[themeName: string]: string
}
+interface ScriptAttributeObject {
+ [attributeName: string]: string
+}
+
export interface UseThemeProps {
/** List of all available theme names */
themes: string[]
@@ -38,6 +42,8 @@ export interface ThemeProviderProps {
value?: ValueObject
/** Nonce string to pass to the inline script for CSP headers */
nonce?: string
+ /** Object of attributes and their values to pass to the inline script */
+ scriptAttribute?: ScriptAttributeObject
children?: React.ReactNode
}
From 368bc2a5e051c5a89abf4379c0034db564b99d78 Mon Sep 17 00:00:00 2001
From: Andrea Cassani <32062066+andreacassani@users.noreply.github.com>
Date: Fri, 25 Nov 2022 20:25:51 +0100
Subject: [PATCH 3/4] Wording
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index d054391..1d8d4d8 100644
--- a/README.md
+++ b/README.md
@@ -111,7 +111,7 @@ All your theme configuration is passed to ThemeProvider.
- `value`: Optional mapping of theme name to attribute value
- value is an `object` where key is the theme name and value is the attribute value ([example](#differing-dom-attribute-and-theme-name))
- `nonce`: Optional nonce passed to the injected `script` tag, used to allow-list the next-themes script in your CSP
-- `scriptAttribute`: Optional object used to pass custom pair of attributes and their values to the injected `script` ([example](#using-with-cloudflare-rocket-loader))
+- `scriptAttribute`: Optional object used to pass custom pairs of attributes and their values to the injected `script` ([example](#using-with-cloudflare-rocket-loader))
### useTheme
@@ -224,7 +224,7 @@ document.documentElement.getAttribute('data-theme')
### Using with Cloudflare Rocket Loader
-[Rocket Loader](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/) is a Cloudflare optimization that defers the loading of inline and external scripts to prioritizes the website content. Since next-themes relies on a script injection to avoid screen flashing on page load, Rocket Loader breaks this functionality. Individual scripts [can be ignored](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/ignore-javascripts/) by adding the `data-cfasync="false"` attribute to the script tag:
+[Rocket Loader](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/) is a Cloudflare optimization that defers the loading of inline and external scripts to prioritize the website content. Since next-themes relies on a script injection to avoid screen flashing on page load, Rocket Loader breaks this functionality. Individual scripts [can be ignored](https://developers.cloudflare.com/fundamentals/speed/rocket-loader/ignore-javascripts/) by adding the `data-cfasync="false"` attribute to the script tag:
```js
From 41d9b2042400e1f647109fa099c49713cfa49349 Mon Sep 17 00:00:00 2001
From: Paco <34928425+pacocoursey@users.noreply.github.com>
Date: Sun, 3 Nov 2024 19:16:29 -0800
Subject: [PATCH 4/4] fix types, add test
---
next-themes/__tests__/index.test.tsx | 14 ++++++++++++++
next-themes/src/index.tsx | 10 +++++++---
next-themes/src/types.ts | 14 ++++++++++----
3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/next-themes/__tests__/index.test.tsx b/next-themes/__tests__/index.test.tsx
index c102403..7ebb831 100644
--- a/next-themes/__tests__/index.test.tsx
+++ b/next-themes/__tests__/index.test.tsx
@@ -460,3 +460,17 @@ describe('setTheme', () => {
expect(result.current.resolvedTheme).toBe('light')
})
})
+
+describe('inline script', () => {
+ test('should pass props to script', () => {
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ expect(document.querySelector('script[data-test="1234"]')).toBeTruthy()
+ })
+})
diff --git a/next-themes/src/index.tsx b/next-themes/src/index.tsx
index 7c37224..0a53b02 100644
--- a/next-themes/src/index.tsx
+++ b/next-themes/src/index.tsx
@@ -33,7 +33,8 @@ const Theme = ({
attribute = 'data-theme',
value,
children,
- nonce
+ nonce,
+ scriptProps
}: ThemeProviderProps) => {
const [theme, setThemeState] = React.useState(() => getTheme(storageKey, defaultTheme))
const [resolvedTheme, setResolvedTheme] = React.useState(() => getTheme(storageKey))
@@ -161,7 +162,8 @@ const Theme = ({
defaultTheme,
value,
themes,
- nonce
+ nonce,
+ scriptProps
}}
/>
@@ -180,7 +182,8 @@ const ThemeScript = React.memo(
defaultTheme,
value,
themes,
- nonce
+ nonce,
+ scriptProps
}: Omit & { defaultTheme: string }) => {
const scriptArgs = JSON.stringify([
attribute,
@@ -195,6 +198,7 @@ const ThemeScript = React.memo(
return (