@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 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
- **What it renders:**
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%; --primary:221.2 83.2% 53.3%; ... }
112
- .dark { --background:222.2 84% 4.9%; --primary:217.2 91.2% 59.8%; ... }
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
- export { DhemeScript, type DhemeScriptProps, type GenerateThemeStylesOptions, generateThemeStyles, getModeFromCookie, getParamsFromCookie, themeCache };
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
- export { DhemeScript, type DhemeScriptProps, type GenerateThemeStylesOptions, generateThemeStyles, getModeFromCookie, getParamsFromCookie, themeCache };
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 lightCSS = (0, import_utils.themeToCSS)(themeData, "light");
102
- const darkCSS = (0, import_utils.themeToCSS)(themeData, "dark");
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 lightCSS = themeToCSS(themeData, "light");
62
- const darkCSS = themeToCSS(themeData, "dark");
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.8.0",
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.8.0"
59
+ "@dheme/react": "^2.12.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/react": "^18.2.0",