@dheme/next 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/index.d.mts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +19 -0
- package/dist/index.mjs +19 -0
- package/dist/server.d.mts +22 -1
- package/dist/server.d.ts +22 -1
- package/dist/server.js +28 -2
- package/dist/server.mjs +27 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -87,6 +87,7 @@ Fetches the theme on the server and renders inline `<style>` + `<script>` tags.
|
|
|
87
87
|
radius: 0.75,
|
|
88
88
|
saturationAdjust: 10,
|
|
89
89
|
borderIsColored: false,
|
|
90
|
+
tailwindVersion: 'v4', // 'v3' | 'v4' (default: 'v4')
|
|
90
91
|
}}
|
|
91
92
|
defaultMode="light" // 'light' | 'dark' (default: 'light')
|
|
92
93
|
baseUrl="http://localhost:3005" // Override API URL (optional)
|
|
@@ -103,13 +104,15 @@ Fetches the theme on the server and renders inline `<style>` + `<script>` tags.
|
|
|
103
104
|
| `baseUrl` | `string` | - | Override API base URL. |
|
|
104
105
|
| `nonce` | `string` | - | CSP nonce for style and script tags. |
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
> **`themeParams.tailwindVersion`** controls the CSS variable format in the inlined `<style>`. Use `'v3'` for `hsl(var(--token))` (Tailwind v3 / shadcn/ui) or `'v4'` (default) for `var(--token)` (Tailwind v4 / `@theme inline`). Must match the value used in `<DhemeProvider>`.
|
|
108
|
+
|
|
109
|
+
**What it renders (Tailwind v4 — default):**
|
|
107
110
|
|
|
108
111
|
```html
|
|
109
112
|
<!-- CSS for both modes — parsed before paint -->
|
|
110
113
|
<style>
|
|
111
|
-
:root { --background:0 0% 100
|
|
112
|
-
.dark { --background:222.2 84% 4.9
|
|
114
|
+
:root { --background:hsl(0 0% 100%); --primary:hsl(221.2 83.2% 53.3%); ... }
|
|
115
|
+
.dark { --background:hsl(222.2 84% 4.9%); --primary:hsl(217.2 91.2% 59.8%); ... }
|
|
113
116
|
</style>
|
|
114
117
|
|
|
115
118
|
<!-- Mode detection — applies .dark class if needed -->
|
|
@@ -428,10 +431,7 @@ import type {
|
|
|
428
431
|
} from '@dheme/next';
|
|
429
432
|
|
|
430
433
|
// Server types
|
|
431
|
-
import type {
|
|
432
|
-
DhemeScriptProps,
|
|
433
|
-
GenerateThemeStylesOptions,
|
|
434
|
-
} from '@dheme/next/server';
|
|
434
|
+
import type { DhemeScriptProps, GenerateThemeStylesOptions } from '@dheme/next/server';
|
|
435
435
|
```
|
|
436
436
|
|
|
437
437
|
## Related Packages
|
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,20 @@ export { ThemeActionsState, ThemeDataState, ThemeGenerator, ThemeGeneratorProps,
|
|
|
6
6
|
|
|
7
7
|
interface DhemeProviderProps extends DhemeProviderProps$1 {
|
|
8
8
|
cookieSync?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* URL of a proxy route that forwards theme requests server-side,
|
|
11
|
+
* keeping the API key out of the browser entirely.
|
|
12
|
+
*
|
|
13
|
+
* Set up the route with `createDhemeHandler` from `@dheme/next/server`:
|
|
14
|
+
* @example
|
|
15
|
+
* // app/api/dheme/route.ts
|
|
16
|
+
* import { createDhemeHandler } from '@dheme/next/server';
|
|
17
|
+
* export const { POST } = createDhemeHandler({ apiKey: process.env.DHEME_API_KEY! });
|
|
18
|
+
*
|
|
19
|
+
* // layout.tsx
|
|
20
|
+
* <DhemeProvider proxyUrl="/api/dheme" theme="..." />
|
|
21
|
+
*/
|
|
22
|
+
proxyUrl?: string;
|
|
9
23
|
}
|
|
10
24
|
interface GenerateThemeStylesOptions {
|
|
11
25
|
/** API key (obrigatório para uso externo; omitir para rotas internas sem autenticação) */
|
|
@@ -21,6 +35,6 @@ interface GenerateThemeStylesOptions {
|
|
|
21
35
|
onGenerateTheme?: (params: GenerateThemeRequest) => Promise<GenerateThemeResponse>;
|
|
22
36
|
}
|
|
23
37
|
|
|
24
|
-
declare function DhemeProvider({ children, cookieSync, onThemeChange, onModeChange, theme: primaryColor, themeParams, ...props }: DhemeProviderProps): React.ReactElement;
|
|
38
|
+
declare function DhemeProvider({ children, cookieSync, proxyUrl, onThemeChange, onModeChange, onGenerateTheme, theme: primaryColor, themeParams, ...props }: DhemeProviderProps): React.ReactElement;
|
|
25
39
|
|
|
26
40
|
export { DhemeProvider, type DhemeProviderProps, type GenerateThemeStylesOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,20 @@ export { ThemeActionsState, ThemeDataState, ThemeGenerator, ThemeGeneratorProps,
|
|
|
6
6
|
|
|
7
7
|
interface DhemeProviderProps extends DhemeProviderProps$1 {
|
|
8
8
|
cookieSync?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* URL of a proxy route that forwards theme requests server-side,
|
|
11
|
+
* keeping the API key out of the browser entirely.
|
|
12
|
+
*
|
|
13
|
+
* Set up the route with `createDhemeHandler` from `@dheme/next/server`:
|
|
14
|
+
* @example
|
|
15
|
+
* // app/api/dheme/route.ts
|
|
16
|
+
* import { createDhemeHandler } from '@dheme/next/server';
|
|
17
|
+
* export const { POST } = createDhemeHandler({ apiKey: process.env.DHEME_API_KEY! });
|
|
18
|
+
*
|
|
19
|
+
* // layout.tsx
|
|
20
|
+
* <DhemeProvider proxyUrl="/api/dheme" theme="..." />
|
|
21
|
+
*/
|
|
22
|
+
proxyUrl?: string;
|
|
9
23
|
}
|
|
10
24
|
interface GenerateThemeStylesOptions {
|
|
11
25
|
/** API key (obrigatório para uso externo; omitir para rotas internas sem autenticação) */
|
|
@@ -21,6 +35,6 @@ interface GenerateThemeStylesOptions {
|
|
|
21
35
|
onGenerateTheme?: (params: GenerateThemeRequest) => Promise<GenerateThemeResponse>;
|
|
22
36
|
}
|
|
23
37
|
|
|
24
|
-
declare function DhemeProvider({ children, cookieSync, onThemeChange, onModeChange, theme: primaryColor, themeParams, ...props }: DhemeProviderProps): React.ReactElement;
|
|
38
|
+
declare function DhemeProvider({ children, cookieSync, proxyUrl, onThemeChange, onModeChange, onGenerateTheme, theme: primaryColor, themeParams, ...props }: DhemeProviderProps): React.ReactElement;
|
|
25
39
|
|
|
26
40
|
export { DhemeProvider, type DhemeProviderProps, type GenerateThemeStylesOptions };
|
package/dist/index.js
CHANGED
|
@@ -53,8 +53,10 @@ function setCookie(name, value) {
|
|
|
53
53
|
function DhemeProvider({
|
|
54
54
|
children,
|
|
55
55
|
cookieSync = true,
|
|
56
|
+
proxyUrl,
|
|
56
57
|
onThemeChange,
|
|
57
58
|
onModeChange,
|
|
59
|
+
onGenerateTheme,
|
|
58
60
|
theme: primaryColor,
|
|
59
61
|
themeParams,
|
|
60
62
|
...props
|
|
@@ -82,11 +84,28 @@ function DhemeProvider({
|
|
|
82
84
|
},
|
|
83
85
|
[cookieSync, onModeChange]
|
|
84
86
|
);
|
|
87
|
+
const proxyGenerateTheme = (0, import_react.useCallback)(
|
|
88
|
+
async (params) => {
|
|
89
|
+
const res = await fetch(proxyUrl, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: { "Content-Type": "application/json" },
|
|
92
|
+
body: JSON.stringify(params)
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
const body = await res.json().catch(() => ({}));
|
|
96
|
+
throw new Error(body.error ?? `Proxy request failed: ${res.status}`);
|
|
97
|
+
}
|
|
98
|
+
return res.json();
|
|
99
|
+
},
|
|
100
|
+
[proxyUrl]
|
|
101
|
+
);
|
|
102
|
+
const resolvedGenerateTheme = proxyUrl ? proxyGenerateTheme : onGenerateTheme;
|
|
85
103
|
return import_react.default.createElement(import_react2.DhemeProvider, {
|
|
86
104
|
...props,
|
|
87
105
|
theme: primaryColor,
|
|
88
106
|
themeParams,
|
|
89
107
|
persist: true,
|
|
108
|
+
onGenerateTheme: resolvedGenerateTheme,
|
|
90
109
|
onThemeChange: handleThemeChange,
|
|
91
110
|
onModeChange: handleModeChange,
|
|
92
111
|
children
|
package/dist/index.mjs
CHANGED
|
@@ -10,8 +10,10 @@ function setCookie(name, value) {
|
|
|
10
10
|
function DhemeProvider({
|
|
11
11
|
children,
|
|
12
12
|
cookieSync = true,
|
|
13
|
+
proxyUrl,
|
|
13
14
|
onThemeChange,
|
|
14
15
|
onModeChange,
|
|
16
|
+
onGenerateTheme,
|
|
15
17
|
theme: primaryColor,
|
|
16
18
|
themeParams,
|
|
17
19
|
...props
|
|
@@ -39,11 +41,28 @@ function DhemeProvider({
|
|
|
39
41
|
},
|
|
40
42
|
[cookieSync, onModeChange]
|
|
41
43
|
);
|
|
44
|
+
const proxyGenerateTheme = useCallback(
|
|
45
|
+
async (params) => {
|
|
46
|
+
const res = await fetch(proxyUrl, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "Content-Type": "application/json" },
|
|
49
|
+
body: JSON.stringify(params)
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
const body = await res.json().catch(() => ({}));
|
|
53
|
+
throw new Error(body.error ?? `Proxy request failed: ${res.status}`);
|
|
54
|
+
}
|
|
55
|
+
return res.json();
|
|
56
|
+
},
|
|
57
|
+
[proxyUrl]
|
|
58
|
+
);
|
|
59
|
+
const resolvedGenerateTheme = proxyUrl ? proxyGenerateTheme : onGenerateTheme;
|
|
42
60
|
return React.createElement(ReactDhemeProvider, {
|
|
43
61
|
...props,
|
|
44
62
|
theme: primaryColor,
|
|
45
63
|
themeParams,
|
|
46
64
|
persist: true,
|
|
65
|
+
onGenerateTheme: resolvedGenerateTheme,
|
|
47
66
|
onThemeChange: handleThemeChange,
|
|
48
67
|
onModeChange: handleModeChange,
|
|
49
68
|
children
|
package/dist/server.d.mts
CHANGED
|
@@ -59,4 +59,25 @@ declare class ThemeCache {
|
|
|
59
59
|
}
|
|
60
60
|
declare const themeCache: ThemeCache;
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
interface DhemeHandlerConfig {
|
|
63
|
+
/** API key — keep in an environment variable, never in client code. */
|
|
64
|
+
apiKey: string;
|
|
65
|
+
baseUrl?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a Next.js App Router Route Handler that proxies theme generation
|
|
69
|
+
* requests server-side, so the API key is never exposed to the browser.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // app/api/dheme/route.ts
|
|
73
|
+
* import { createDhemeHandler } from '@dheme/next/server';
|
|
74
|
+
* export const { POST } = createDhemeHandler({ apiKey: process.env.DHEME_API_KEY! });
|
|
75
|
+
*
|
|
76
|
+
* // Then in your layout, use proxyUrl instead of apiKey:
|
|
77
|
+
* // <DhemeProvider proxyUrl="/api/dheme" theme="..." />
|
|
78
|
+
*/
|
|
79
|
+
declare function createDhemeHandler(config: DhemeHandlerConfig): {
|
|
80
|
+
POST: (request: Request) => Promise<Response>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export { type DhemeHandlerConfig, DhemeScript, type DhemeScriptProps, type GenerateThemeStylesOptions, createDhemeHandler, generateThemeStyles, getModeFromCookie, getParamsFromCookie, themeCache };
|
package/dist/server.d.ts
CHANGED
|
@@ -59,4 +59,25 @@ declare class ThemeCache {
|
|
|
59
59
|
}
|
|
60
60
|
declare const themeCache: ThemeCache;
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
interface DhemeHandlerConfig {
|
|
63
|
+
/** API key — keep in an environment variable, never in client code. */
|
|
64
|
+
apiKey: string;
|
|
65
|
+
baseUrl?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a Next.js App Router Route Handler that proxies theme generation
|
|
69
|
+
* requests server-side, so the API key is never exposed to the browser.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // app/api/dheme/route.ts
|
|
73
|
+
* import { createDhemeHandler } from '@dheme/next/server';
|
|
74
|
+
* export const { POST } = createDhemeHandler({ apiKey: process.env.DHEME_API_KEY! });
|
|
75
|
+
*
|
|
76
|
+
* // Then in your layout, use proxyUrl instead of apiKey:
|
|
77
|
+
* // <DhemeProvider proxyUrl="/api/dheme" theme="..." />
|
|
78
|
+
*/
|
|
79
|
+
declare function createDhemeHandler(config: DhemeHandlerConfig): {
|
|
80
|
+
POST: (request: Request) => Promise<Response>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export { type DhemeHandlerConfig, DhemeScript, type DhemeScriptProps, type GenerateThemeStylesOptions, createDhemeHandler, generateThemeStyles, getModeFromCookie, getParamsFromCookie, themeCache };
|
package/dist/server.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var server_exports = {};
|
|
32
32
|
__export(server_exports, {
|
|
33
33
|
DhemeScript: () => DhemeScript,
|
|
34
|
+
createDhemeHandler: () => createDhemeHandler,
|
|
34
35
|
generateThemeStyles: () => generateThemeStyles,
|
|
35
36
|
getModeFromCookie: () => getModeFromCookie,
|
|
36
37
|
getParamsFromCookie: () => getParamsFromCookie,
|
|
@@ -98,8 +99,9 @@ async function DhemeScript({
|
|
|
98
99
|
}
|
|
99
100
|
themeCache.set(cacheKey, themeData);
|
|
100
101
|
}
|
|
101
|
-
const
|
|
102
|
-
const
|
|
102
|
+
const tailwindVersion = params.tailwindVersion ?? "v4";
|
|
103
|
+
const lightCSS = (0, import_utils.themeToCSS)(themeData, "light", tailwindVersion);
|
|
104
|
+
const darkCSS = (0, import_utils.themeToCSS)(themeData, "dark", tailwindVersion);
|
|
103
105
|
const styleContent = `:root{${lightCSS}}.dark{${darkCSS}}`;
|
|
104
106
|
const scriptContent = (0, import_utils.getNextBlockingScriptPayload)(defaultMode);
|
|
105
107
|
const styleProps = {
|
|
@@ -170,9 +172,33 @@ async function getParamsFromCookie() {
|
|
|
170
172
|
return null;
|
|
171
173
|
}
|
|
172
174
|
}
|
|
175
|
+
|
|
176
|
+
// src/server/handler.ts
|
|
177
|
+
var import_sdk3 = require("@dheme/sdk");
|
|
178
|
+
function createDhemeHandler(config) {
|
|
179
|
+
const client = new import_sdk3.DhemeClient({ apiKey: config.apiKey, baseUrl: config.baseUrl });
|
|
180
|
+
async function POST(request) {
|
|
181
|
+
let body;
|
|
182
|
+
try {
|
|
183
|
+
body = await request.json();
|
|
184
|
+
} catch {
|
|
185
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const response = await client.generateTheme(body);
|
|
189
|
+
return Response.json(response.data);
|
|
190
|
+
} catch (err) {
|
|
191
|
+
const message = err instanceof Error ? err.message : "Internal server error";
|
|
192
|
+
const status = message.includes("429") || message.toLowerCase().includes("rate limit") ? 429 : 500;
|
|
193
|
+
return Response.json({ error: message }, { status });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { POST };
|
|
197
|
+
}
|
|
173
198
|
// Annotate the CommonJS export names for ESM import in node:
|
|
174
199
|
0 && (module.exports = {
|
|
175
200
|
DhemeScript,
|
|
201
|
+
createDhemeHandler,
|
|
176
202
|
generateThemeStyles,
|
|
177
203
|
getModeFromCookie,
|
|
178
204
|
getParamsFromCookie,
|
package/dist/server.mjs
CHANGED
|
@@ -58,8 +58,9 @@ async function DhemeScript({
|
|
|
58
58
|
}
|
|
59
59
|
themeCache.set(cacheKey, themeData);
|
|
60
60
|
}
|
|
61
|
-
const
|
|
62
|
-
const
|
|
61
|
+
const tailwindVersion = params.tailwindVersion ?? "v4";
|
|
62
|
+
const lightCSS = themeToCSS(themeData, "light", tailwindVersion);
|
|
63
|
+
const darkCSS = themeToCSS(themeData, "dark", tailwindVersion);
|
|
63
64
|
const styleContent = `:root{${lightCSS}}.dark{${darkCSS}}`;
|
|
64
65
|
const scriptContent = getNextBlockingScriptPayload(defaultMode);
|
|
65
66
|
const styleProps = {
|
|
@@ -130,8 +131,32 @@ async function getParamsFromCookie() {
|
|
|
130
131
|
return null;
|
|
131
132
|
}
|
|
132
133
|
}
|
|
134
|
+
|
|
135
|
+
// src/server/handler.ts
|
|
136
|
+
import { DhemeClient as DhemeClient3 } from "@dheme/sdk";
|
|
137
|
+
function createDhemeHandler(config) {
|
|
138
|
+
const client = new DhemeClient3({ apiKey: config.apiKey, baseUrl: config.baseUrl });
|
|
139
|
+
async function POST(request) {
|
|
140
|
+
let body;
|
|
141
|
+
try {
|
|
142
|
+
body = await request.json();
|
|
143
|
+
} catch {
|
|
144
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const response = await client.generateTheme(body);
|
|
148
|
+
return Response.json(response.data);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
const message = err instanceof Error ? err.message : "Internal server error";
|
|
151
|
+
const status = message.includes("429") || message.toLowerCase().includes("rate limit") ? 429 : 500;
|
|
152
|
+
return Response.json({ error: message }, { status });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return { POST };
|
|
156
|
+
}
|
|
133
157
|
export {
|
|
134
158
|
DhemeScript,
|
|
159
|
+
createDhemeHandler,
|
|
135
160
|
generateThemeStyles,
|
|
136
161
|
getModeFromCookie,
|
|
137
162
|
getParamsFromCookie,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dheme/next",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Next.js App Router bindings for Dheme SDK with server-side theme generation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@dheme/sdk": "^1.1.0",
|
|
59
|
-
"@dheme/react": "^2.
|
|
59
|
+
"@dheme/react": "^2.12.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/react": "^18.2.0",
|