@dheme/react 2.3.0 → 2.5.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/dist/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +19 -8
- package/dist/index.mjs +16 -5
- package/dist/utils.d.mts +15 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +156 -0
- package/dist/utils.mjs +123 -0
- package/package.json +6 -1
package/dist/index.d.mts
CHANGED
|
@@ -26,6 +26,22 @@ interface DhemeProviderProps {
|
|
|
26
26
|
baseUrl?: string;
|
|
27
27
|
persist?: boolean;
|
|
28
28
|
autoApply?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Custom theme generation function. When provided, replaces the SDK client's
|
|
31
|
+
* generateTheme call entirely. Useful for internal use cases with custom endpoints.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Call an internal proxy route without API key:
|
|
35
|
+
* onGenerateTheme={async (params) => {
|
|
36
|
+
* const res = await fetch('/api/generate-theme/proxy', {
|
|
37
|
+
* method: 'POST',
|
|
38
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
39
|
+
* body: JSON.stringify(params),
|
|
40
|
+
* });
|
|
41
|
+
* return res.json();
|
|
42
|
+
* }}
|
|
43
|
+
*/
|
|
44
|
+
onGenerateTheme?: (params: GenerateThemeRequest) => Promise<GenerateThemeResponse>;
|
|
29
45
|
onThemeChange?: (theme: GenerateThemeResponse) => void;
|
|
30
46
|
onModeChange?: (mode: ThemeMode) => void;
|
|
31
47
|
onError?: (error: Error) => void;
|
|
@@ -36,7 +52,7 @@ interface DhemeScriptProps {
|
|
|
36
52
|
nonce?: string;
|
|
37
53
|
}
|
|
38
54
|
|
|
39
|
-
declare function DhemeProvider({ apiKey, theme: primaryColor, themeParams, defaultMode, baseUrl, persist, autoApply, onThemeChange, onModeChange, onError, children, }: DhemeProviderProps): React__default.ReactElement;
|
|
55
|
+
declare function DhemeProvider({ apiKey, theme: primaryColor, themeParams, defaultMode, baseUrl, persist, autoApply, onGenerateTheme: customGenerateTheme, onThemeChange, onModeChange, onError, children, }: DhemeProviderProps): React__default.ReactElement;
|
|
40
56
|
|
|
41
57
|
declare function DhemeScript({ defaultMode, nonce, }: DhemeScriptProps): React__default.ReactElement;
|
|
42
58
|
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,22 @@ interface DhemeProviderProps {
|
|
|
26
26
|
baseUrl?: string;
|
|
27
27
|
persist?: boolean;
|
|
28
28
|
autoApply?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Custom theme generation function. When provided, replaces the SDK client's
|
|
31
|
+
* generateTheme call entirely. Useful for internal use cases with custom endpoints.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Call an internal proxy route without API key:
|
|
35
|
+
* onGenerateTheme={async (params) => {
|
|
36
|
+
* const res = await fetch('/api/generate-theme/proxy', {
|
|
37
|
+
* method: 'POST',
|
|
38
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
39
|
+
* body: JSON.stringify(params),
|
|
40
|
+
* });
|
|
41
|
+
* return res.json();
|
|
42
|
+
* }}
|
|
43
|
+
*/
|
|
44
|
+
onGenerateTheme?: (params: GenerateThemeRequest) => Promise<GenerateThemeResponse>;
|
|
29
45
|
onThemeChange?: (theme: GenerateThemeResponse) => void;
|
|
30
46
|
onModeChange?: (mode: ThemeMode) => void;
|
|
31
47
|
onError?: (error: Error) => void;
|
|
@@ -36,7 +52,7 @@ interface DhemeScriptProps {
|
|
|
36
52
|
nonce?: string;
|
|
37
53
|
}
|
|
38
54
|
|
|
39
|
-
declare function DhemeProvider({ apiKey, theme: primaryColor, themeParams, defaultMode, baseUrl, persist, autoApply, onThemeChange, onModeChange, onError, children, }: DhemeProviderProps): React__default.ReactElement;
|
|
55
|
+
declare function DhemeProvider({ apiKey, theme: primaryColor, themeParams, defaultMode, baseUrl, persist, autoApply, onGenerateTheme: customGenerateTheme, onThemeChange, onModeChange, onError, children, }: DhemeProviderProps): React__default.ReactElement;
|
|
40
56
|
|
|
41
57
|
declare function DhemeScript({ defaultMode, nonce, }: DhemeScriptProps): React__default.ReactElement;
|
|
42
58
|
|
package/dist/index.js
CHANGED
|
@@ -29,8 +29,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
|
-
var
|
|
33
|
-
__export(
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
__export(src_exports, {
|
|
34
34
|
DhemeProvider: () => DhemeProvider,
|
|
35
35
|
DhemeScript: () => DhemeScript,
|
|
36
36
|
ThemeActionsContext: () => ThemeActionsContext,
|
|
@@ -48,7 +48,7 @@ __export(index_exports, {
|
|
|
48
48
|
useTheme: () => useTheme,
|
|
49
49
|
useThemeActions: () => useThemeActions
|
|
50
50
|
});
|
|
51
|
-
module.exports = __toCommonJS(
|
|
51
|
+
module.exports = __toCommonJS(src_exports);
|
|
52
52
|
|
|
53
53
|
// src/components/DhemeProvider.tsx
|
|
54
54
|
var import_react3 = __toESM(require("react"));
|
|
@@ -259,12 +259,15 @@ function DhemeProvider({
|
|
|
259
259
|
baseUrl,
|
|
260
260
|
persist = true,
|
|
261
261
|
autoApply = true,
|
|
262
|
+
onGenerateTheme: customGenerateTheme,
|
|
262
263
|
onThemeChange,
|
|
263
264
|
onModeChange,
|
|
264
265
|
onError,
|
|
265
266
|
children
|
|
266
267
|
}) {
|
|
267
268
|
const client = (0, import_react3.useMemo)(() => new import_sdk.DhemeClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
269
|
+
const customGenerateThemeRef = (0, import_react3.useRef)(customGenerateTheme);
|
|
270
|
+
customGenerateThemeRef.current = customGenerateTheme;
|
|
268
271
|
const [theme, setTheme] = (0, import_react3.useState)(null);
|
|
269
272
|
const [mode, setModeState] = (0, import_react3.useState)(() => {
|
|
270
273
|
if (typeof window === "undefined") return defaultMode;
|
|
@@ -303,14 +306,23 @@ function DhemeProvider({
|
|
|
303
306
|
}
|
|
304
307
|
}
|
|
305
308
|
}, [theme, mode, autoApply]);
|
|
309
|
+
const fetchTheme = (0, import_react3.useCallback)(
|
|
310
|
+
async (params) => {
|
|
311
|
+
if (customGenerateThemeRef.current) {
|
|
312
|
+
return customGenerateThemeRef.current(params);
|
|
313
|
+
}
|
|
314
|
+
const response = await client.generateTheme(params);
|
|
315
|
+
return response.data;
|
|
316
|
+
},
|
|
317
|
+
[client]
|
|
318
|
+
);
|
|
306
319
|
const generateTheme = (0, import_react3.useCallback)(
|
|
307
320
|
async (params) => {
|
|
308
321
|
abortRef.current?.abort();
|
|
309
322
|
setIsLoading(true);
|
|
310
323
|
setError(null);
|
|
311
324
|
try {
|
|
312
|
-
const
|
|
313
|
-
const data = response.data;
|
|
325
|
+
const data = await fetchTheme(params);
|
|
314
326
|
setTheme(data);
|
|
315
327
|
setIsReady(true);
|
|
316
328
|
if (autoApplyRef.current) {
|
|
@@ -330,7 +342,7 @@ function DhemeProvider({
|
|
|
330
342
|
setIsLoading(false);
|
|
331
343
|
}
|
|
332
344
|
},
|
|
333
|
-
[
|
|
345
|
+
[fetchTheme]
|
|
334
346
|
);
|
|
335
347
|
const clearTheme = (0, import_react3.useCallback)(() => {
|
|
336
348
|
setTheme(null);
|
|
@@ -353,9 +365,8 @@ function DhemeProvider({
|
|
|
353
365
|
if (autoApply) applyThemeCSSVariables(cached, mode);
|
|
354
366
|
const controller = new AbortController();
|
|
355
367
|
abortRef.current = controller;
|
|
356
|
-
|
|
368
|
+
fetchTheme(params).then((data) => {
|
|
357
369
|
if (controller.signal.aborted) return;
|
|
358
|
-
const data = response.data;
|
|
359
370
|
const cachedLight = JSON.stringify(cached.colors.light);
|
|
360
371
|
const freshLight = JSON.stringify(data.colors.light);
|
|
361
372
|
if (cachedLight !== freshLight) {
|
package/dist/index.mjs
CHANGED
|
@@ -209,12 +209,15 @@ function DhemeProvider({
|
|
|
209
209
|
baseUrl,
|
|
210
210
|
persist = true,
|
|
211
211
|
autoApply = true,
|
|
212
|
+
onGenerateTheme: customGenerateTheme,
|
|
212
213
|
onThemeChange,
|
|
213
214
|
onModeChange,
|
|
214
215
|
onError,
|
|
215
216
|
children
|
|
216
217
|
}) {
|
|
217
218
|
const client = useMemo(() => new DhemeClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
|
|
219
|
+
const customGenerateThemeRef = useRef(customGenerateTheme);
|
|
220
|
+
customGenerateThemeRef.current = customGenerateTheme;
|
|
218
221
|
const [theme, setTheme] = useState(null);
|
|
219
222
|
const [mode, setModeState] = useState(() => {
|
|
220
223
|
if (typeof window === "undefined") return defaultMode;
|
|
@@ -253,14 +256,23 @@ function DhemeProvider({
|
|
|
253
256
|
}
|
|
254
257
|
}
|
|
255
258
|
}, [theme, mode, autoApply]);
|
|
259
|
+
const fetchTheme = useCallback(
|
|
260
|
+
async (params) => {
|
|
261
|
+
if (customGenerateThemeRef.current) {
|
|
262
|
+
return customGenerateThemeRef.current(params);
|
|
263
|
+
}
|
|
264
|
+
const response = await client.generateTheme(params);
|
|
265
|
+
return response.data;
|
|
266
|
+
},
|
|
267
|
+
[client]
|
|
268
|
+
);
|
|
256
269
|
const generateTheme = useCallback(
|
|
257
270
|
async (params) => {
|
|
258
271
|
abortRef.current?.abort();
|
|
259
272
|
setIsLoading(true);
|
|
260
273
|
setError(null);
|
|
261
274
|
try {
|
|
262
|
-
const
|
|
263
|
-
const data = response.data;
|
|
275
|
+
const data = await fetchTheme(params);
|
|
264
276
|
setTheme(data);
|
|
265
277
|
setIsReady(true);
|
|
266
278
|
if (autoApplyRef.current) {
|
|
@@ -280,7 +292,7 @@ function DhemeProvider({
|
|
|
280
292
|
setIsLoading(false);
|
|
281
293
|
}
|
|
282
294
|
},
|
|
283
|
-
[
|
|
295
|
+
[fetchTheme]
|
|
284
296
|
);
|
|
285
297
|
const clearTheme = useCallback(() => {
|
|
286
298
|
setTheme(null);
|
|
@@ -303,9 +315,8 @@ function DhemeProvider({
|
|
|
303
315
|
if (autoApply) applyThemeCSSVariables(cached, mode);
|
|
304
316
|
const controller = new AbortController();
|
|
305
317
|
abortRef.current = controller;
|
|
306
|
-
|
|
318
|
+
fetchTheme(params).then((data) => {
|
|
307
319
|
if (controller.signal.aborted) return;
|
|
308
|
-
const data = response.data;
|
|
309
320
|
const cachedLight = JSON.stringify(cached.colors.light);
|
|
310
321
|
const freshLight = JSON.stringify(data.colors.light);
|
|
311
322
|
if (cachedLight !== freshLight) {
|
package/dist/utils.d.mts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GenerateThemeResponse, GenerateThemeRequest } from '@dheme/sdk';
|
|
2
|
+
|
|
3
|
+
type ThemeMode = 'light' | 'dark';
|
|
4
|
+
|
|
5
|
+
declare function themeToCSS(theme: GenerateThemeResponse, mode: ThemeMode): string;
|
|
6
|
+
declare function themeToCSSBothModes(theme: GenerateThemeResponse): string;
|
|
7
|
+
declare function applyThemeCSSVariables(theme: GenerateThemeResponse, mode: ThemeMode): void;
|
|
8
|
+
declare function removeThemeCSSVariables(): void;
|
|
9
|
+
|
|
10
|
+
declare function buildCacheKey(params: GenerateThemeRequest): string;
|
|
11
|
+
|
|
12
|
+
declare function getBlockingScriptPayload(defaultMode: ThemeMode): string;
|
|
13
|
+
declare function getNextBlockingScriptPayload(defaultMode: ThemeMode): string;
|
|
14
|
+
|
|
15
|
+
export { applyThemeCSSVariables, buildCacheKey, getBlockingScriptPayload, getNextBlockingScriptPayload, removeThemeCSSVariables, themeToCSS, themeToCSSBothModes };
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GenerateThemeResponse, GenerateThemeRequest } from '@dheme/sdk';
|
|
2
|
+
|
|
3
|
+
type ThemeMode = 'light' | 'dark';
|
|
4
|
+
|
|
5
|
+
declare function themeToCSS(theme: GenerateThemeResponse, mode: ThemeMode): string;
|
|
6
|
+
declare function themeToCSSBothModes(theme: GenerateThemeResponse): string;
|
|
7
|
+
declare function applyThemeCSSVariables(theme: GenerateThemeResponse, mode: ThemeMode): void;
|
|
8
|
+
declare function removeThemeCSSVariables(): void;
|
|
9
|
+
|
|
10
|
+
declare function buildCacheKey(params: GenerateThemeRequest): string;
|
|
11
|
+
|
|
12
|
+
declare function getBlockingScriptPayload(defaultMode: ThemeMode): string;
|
|
13
|
+
declare function getNextBlockingScriptPayload(defaultMode: ThemeMode): string;
|
|
14
|
+
|
|
15
|
+
export { applyThemeCSSVariables, buildCacheKey, getBlockingScriptPayload, getNextBlockingScriptPayload, removeThemeCSSVariables, themeToCSS, themeToCSSBothModes };
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/utils.ts
|
|
21
|
+
var utils_exports = {};
|
|
22
|
+
__export(utils_exports, {
|
|
23
|
+
applyThemeCSSVariables: () => applyThemeCSSVariables,
|
|
24
|
+
buildCacheKey: () => buildCacheKey,
|
|
25
|
+
getBlockingScriptPayload: () => getBlockingScriptPayload,
|
|
26
|
+
getNextBlockingScriptPayload: () => getNextBlockingScriptPayload,
|
|
27
|
+
removeThemeCSSVariables: () => removeThemeCSSVariables,
|
|
28
|
+
themeToCSS: () => themeToCSS,
|
|
29
|
+
themeToCSSBothModes: () => themeToCSSBothModes
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(utils_exports);
|
|
32
|
+
|
|
33
|
+
// src/constants.ts
|
|
34
|
+
var CSS_TOKEN_KEYS = [
|
|
35
|
+
"background",
|
|
36
|
+
"foreground",
|
|
37
|
+
"card",
|
|
38
|
+
"cardForeground",
|
|
39
|
+
"popover",
|
|
40
|
+
"popoverForeground",
|
|
41
|
+
"primary",
|
|
42
|
+
"primaryForeground",
|
|
43
|
+
"secondary",
|
|
44
|
+
"secondaryForeground",
|
|
45
|
+
"muted",
|
|
46
|
+
"mutedForeground",
|
|
47
|
+
"accent",
|
|
48
|
+
"accentForeground",
|
|
49
|
+
"destructive",
|
|
50
|
+
"destructiveForeground",
|
|
51
|
+
"border",
|
|
52
|
+
"input",
|
|
53
|
+
"ring"
|
|
54
|
+
];
|
|
55
|
+
var TOKEN_TO_CSS_VAR = {
|
|
56
|
+
background: "--background",
|
|
57
|
+
foreground: "--foreground",
|
|
58
|
+
card: "--card",
|
|
59
|
+
cardForeground: "--card-foreground",
|
|
60
|
+
popover: "--popover",
|
|
61
|
+
popoverForeground: "--popover-foreground",
|
|
62
|
+
primary: "--primary",
|
|
63
|
+
primaryForeground: "--primary-foreground",
|
|
64
|
+
secondary: "--secondary",
|
|
65
|
+
secondaryForeground: "--secondary-foreground",
|
|
66
|
+
muted: "--muted",
|
|
67
|
+
mutedForeground: "--muted-foreground",
|
|
68
|
+
accent: "--accent",
|
|
69
|
+
accentForeground: "--accent-foreground",
|
|
70
|
+
destructive: "--destructive",
|
|
71
|
+
destructiveForeground: "--destructive-foreground",
|
|
72
|
+
border: "--border",
|
|
73
|
+
input: "--input",
|
|
74
|
+
ring: "--ring"
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/utils/cssVariables.ts
|
|
78
|
+
function formatHSL(color) {
|
|
79
|
+
return `${color.h} ${color.s}% ${color.l}%`;
|
|
80
|
+
}
|
|
81
|
+
function themeToCSS(theme, mode) {
|
|
82
|
+
const colors = theme.colors[mode];
|
|
83
|
+
if (!colors) return "";
|
|
84
|
+
const parts = [];
|
|
85
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
86
|
+
const color = colors[key];
|
|
87
|
+
if (color) {
|
|
88
|
+
parts.push(`${TOKEN_TO_CSS_VAR[key]}:${formatHSL(color)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (theme.radius != null) {
|
|
92
|
+
parts.push(`--radius:${theme.radius}rem`);
|
|
93
|
+
}
|
|
94
|
+
return parts.join(";");
|
|
95
|
+
}
|
|
96
|
+
function themeToCSSBothModes(theme) {
|
|
97
|
+
const lightCSS = themeToCSS(theme, "light");
|
|
98
|
+
const darkCSS = themeToCSS(theme, "dark");
|
|
99
|
+
return `:root{${lightCSS}}.dark{${darkCSS}}`;
|
|
100
|
+
}
|
|
101
|
+
function applyThemeCSSVariables(theme, mode) {
|
|
102
|
+
if (typeof document === "undefined") return;
|
|
103
|
+
const colors = theme.colors[mode];
|
|
104
|
+
if (!colors) return;
|
|
105
|
+
const style = document.documentElement.style;
|
|
106
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
107
|
+
const color = colors[key];
|
|
108
|
+
if (color) {
|
|
109
|
+
style.setProperty(TOKEN_TO_CSS_VAR[key], formatHSL(color));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (theme.radius != null) {
|
|
113
|
+
style.setProperty("--radius", `${theme.radius}rem`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function removeThemeCSSVariables() {
|
|
117
|
+
if (typeof document === "undefined") return;
|
|
118
|
+
const style = document.documentElement.style;
|
|
119
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
120
|
+
style.removeProperty(TOKEN_TO_CSS_VAR[key]);
|
|
121
|
+
}
|
|
122
|
+
style.removeProperty("--radius");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/utils/cacheKey.ts
|
|
126
|
+
function buildCacheKey(params) {
|
|
127
|
+
const normalized = {
|
|
128
|
+
t: params.theme.toLowerCase().replace("#", ""),
|
|
129
|
+
s: (params.secondaryColor || "").toLowerCase().replace("#", ""),
|
|
130
|
+
r: params.radius ?? 0.5,
|
|
131
|
+
sa: params.saturationAdjust ?? 0,
|
|
132
|
+
la: params.lightnessAdjust ?? 0,
|
|
133
|
+
ca: params.contrastAdjust ?? 0,
|
|
134
|
+
ci: params.cardIsColored ?? false,
|
|
135
|
+
bi: params.backgroundIsColored ?? true
|
|
136
|
+
};
|
|
137
|
+
return JSON.stringify(normalized);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/utils/scriptPayload.ts
|
|
141
|
+
function getBlockingScriptPayload(defaultMode) {
|
|
142
|
+
return `(function(){try{var p=localStorage.getItem('dheme-params');if(!p)return;var params=JSON.parse(p);var n={t:(params.theme||'').toLowerCase().replace('#',''),s:(params.secondaryColor||'').toLowerCase().replace('#',''),r:params.radius!=null?params.radius:0.5,sa:params.saturationAdjust||0,la:params.lightnessAdjust||0,ca:params.contrastAdjust||0,ci:!!params.cardIsColored,bi:params.backgroundIsColored!=null?params.backgroundIsColored:true};var key='dheme-cache:'+JSON.stringify(n);var c=localStorage.getItem(key);if(!c)return;var theme=JSON.parse(c);var mode=localStorage.getItem('dheme-mode')||'${defaultMode}';var colors=theme.colors[mode];if(!colors)return;var d=document.documentElement.style;var m={background:'--background',foreground:'--foreground',card:'--card',cardForeground:'--card-foreground',popover:'--popover',popoverForeground:'--popover-foreground',primary:'--primary',primaryForeground:'--primary-foreground',secondary:'--secondary',secondaryForeground:'--secondary-foreground',muted:'--muted',mutedForeground:'--muted-foreground',accent:'--accent',accentForeground:'--accent-foreground',destructive:'--destructive',destructiveForeground:'--destructive-foreground',border:'--border',input:'--input',ring:'--ring'};for(var k in m){if(colors[k]){var v=colors[k];d.setProperty(m[k],v.h+' '+v.s+'% '+v.l+'%')}}if(theme.radius!=null)d.setProperty('--radius',theme.radius+'rem');if(mode==='dark')document.documentElement.classList.add('dark');else document.documentElement.classList.remove('dark')}catch(e){}})()`;
|
|
143
|
+
}
|
|
144
|
+
function getNextBlockingScriptPayload(defaultMode) {
|
|
145
|
+
return `(function(){try{var m=document.cookie.match(/dheme-mode=(\\w+)/);var mode=m?m[1]:null;if(!mode){mode=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'${defaultMode}'}if(mode==='dark'){document.documentElement.classList.add('dark')}else{document.documentElement.classList.remove('dark')}}catch(e){}})()`;
|
|
146
|
+
}
|
|
147
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
148
|
+
0 && (module.exports = {
|
|
149
|
+
applyThemeCSSVariables,
|
|
150
|
+
buildCacheKey,
|
|
151
|
+
getBlockingScriptPayload,
|
|
152
|
+
getNextBlockingScriptPayload,
|
|
153
|
+
removeThemeCSSVariables,
|
|
154
|
+
themeToCSS,
|
|
155
|
+
themeToCSSBothModes
|
|
156
|
+
});
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var CSS_TOKEN_KEYS = [
|
|
3
|
+
"background",
|
|
4
|
+
"foreground",
|
|
5
|
+
"card",
|
|
6
|
+
"cardForeground",
|
|
7
|
+
"popover",
|
|
8
|
+
"popoverForeground",
|
|
9
|
+
"primary",
|
|
10
|
+
"primaryForeground",
|
|
11
|
+
"secondary",
|
|
12
|
+
"secondaryForeground",
|
|
13
|
+
"muted",
|
|
14
|
+
"mutedForeground",
|
|
15
|
+
"accent",
|
|
16
|
+
"accentForeground",
|
|
17
|
+
"destructive",
|
|
18
|
+
"destructiveForeground",
|
|
19
|
+
"border",
|
|
20
|
+
"input",
|
|
21
|
+
"ring"
|
|
22
|
+
];
|
|
23
|
+
var TOKEN_TO_CSS_VAR = {
|
|
24
|
+
background: "--background",
|
|
25
|
+
foreground: "--foreground",
|
|
26
|
+
card: "--card",
|
|
27
|
+
cardForeground: "--card-foreground",
|
|
28
|
+
popover: "--popover",
|
|
29
|
+
popoverForeground: "--popover-foreground",
|
|
30
|
+
primary: "--primary",
|
|
31
|
+
primaryForeground: "--primary-foreground",
|
|
32
|
+
secondary: "--secondary",
|
|
33
|
+
secondaryForeground: "--secondary-foreground",
|
|
34
|
+
muted: "--muted",
|
|
35
|
+
mutedForeground: "--muted-foreground",
|
|
36
|
+
accent: "--accent",
|
|
37
|
+
accentForeground: "--accent-foreground",
|
|
38
|
+
destructive: "--destructive",
|
|
39
|
+
destructiveForeground: "--destructive-foreground",
|
|
40
|
+
border: "--border",
|
|
41
|
+
input: "--input",
|
|
42
|
+
ring: "--ring"
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/utils/cssVariables.ts
|
|
46
|
+
function formatHSL(color) {
|
|
47
|
+
return `${color.h} ${color.s}% ${color.l}%`;
|
|
48
|
+
}
|
|
49
|
+
function themeToCSS(theme, mode) {
|
|
50
|
+
const colors = theme.colors[mode];
|
|
51
|
+
if (!colors) return "";
|
|
52
|
+
const parts = [];
|
|
53
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
54
|
+
const color = colors[key];
|
|
55
|
+
if (color) {
|
|
56
|
+
parts.push(`${TOKEN_TO_CSS_VAR[key]}:${formatHSL(color)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (theme.radius != null) {
|
|
60
|
+
parts.push(`--radius:${theme.radius}rem`);
|
|
61
|
+
}
|
|
62
|
+
return parts.join(";");
|
|
63
|
+
}
|
|
64
|
+
function themeToCSSBothModes(theme) {
|
|
65
|
+
const lightCSS = themeToCSS(theme, "light");
|
|
66
|
+
const darkCSS = themeToCSS(theme, "dark");
|
|
67
|
+
return `:root{${lightCSS}}.dark{${darkCSS}}`;
|
|
68
|
+
}
|
|
69
|
+
function applyThemeCSSVariables(theme, mode) {
|
|
70
|
+
if (typeof document === "undefined") return;
|
|
71
|
+
const colors = theme.colors[mode];
|
|
72
|
+
if (!colors) return;
|
|
73
|
+
const style = document.documentElement.style;
|
|
74
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
75
|
+
const color = colors[key];
|
|
76
|
+
if (color) {
|
|
77
|
+
style.setProperty(TOKEN_TO_CSS_VAR[key], formatHSL(color));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (theme.radius != null) {
|
|
81
|
+
style.setProperty("--radius", `${theme.radius}rem`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function removeThemeCSSVariables() {
|
|
85
|
+
if (typeof document === "undefined") return;
|
|
86
|
+
const style = document.documentElement.style;
|
|
87
|
+
for (const key of CSS_TOKEN_KEYS) {
|
|
88
|
+
style.removeProperty(TOKEN_TO_CSS_VAR[key]);
|
|
89
|
+
}
|
|
90
|
+
style.removeProperty("--radius");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/utils/cacheKey.ts
|
|
94
|
+
function buildCacheKey(params) {
|
|
95
|
+
const normalized = {
|
|
96
|
+
t: params.theme.toLowerCase().replace("#", ""),
|
|
97
|
+
s: (params.secondaryColor || "").toLowerCase().replace("#", ""),
|
|
98
|
+
r: params.radius ?? 0.5,
|
|
99
|
+
sa: params.saturationAdjust ?? 0,
|
|
100
|
+
la: params.lightnessAdjust ?? 0,
|
|
101
|
+
ca: params.contrastAdjust ?? 0,
|
|
102
|
+
ci: params.cardIsColored ?? false,
|
|
103
|
+
bi: params.backgroundIsColored ?? true
|
|
104
|
+
};
|
|
105
|
+
return JSON.stringify(normalized);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/utils/scriptPayload.ts
|
|
109
|
+
function getBlockingScriptPayload(defaultMode) {
|
|
110
|
+
return `(function(){try{var p=localStorage.getItem('dheme-params');if(!p)return;var params=JSON.parse(p);var n={t:(params.theme||'').toLowerCase().replace('#',''),s:(params.secondaryColor||'').toLowerCase().replace('#',''),r:params.radius!=null?params.radius:0.5,sa:params.saturationAdjust||0,la:params.lightnessAdjust||0,ca:params.contrastAdjust||0,ci:!!params.cardIsColored,bi:params.backgroundIsColored!=null?params.backgroundIsColored:true};var key='dheme-cache:'+JSON.stringify(n);var c=localStorage.getItem(key);if(!c)return;var theme=JSON.parse(c);var mode=localStorage.getItem('dheme-mode')||'${defaultMode}';var colors=theme.colors[mode];if(!colors)return;var d=document.documentElement.style;var m={background:'--background',foreground:'--foreground',card:'--card',cardForeground:'--card-foreground',popover:'--popover',popoverForeground:'--popover-foreground',primary:'--primary',primaryForeground:'--primary-foreground',secondary:'--secondary',secondaryForeground:'--secondary-foreground',muted:'--muted',mutedForeground:'--muted-foreground',accent:'--accent',accentForeground:'--accent-foreground',destructive:'--destructive',destructiveForeground:'--destructive-foreground',border:'--border',input:'--input',ring:'--ring'};for(var k in m){if(colors[k]){var v=colors[k];d.setProperty(m[k],v.h+' '+v.s+'% '+v.l+'%')}}if(theme.radius!=null)d.setProperty('--radius',theme.radius+'rem');if(mode==='dark')document.documentElement.classList.add('dark');else document.documentElement.classList.remove('dark')}catch(e){}})()`;
|
|
111
|
+
}
|
|
112
|
+
function getNextBlockingScriptPayload(defaultMode) {
|
|
113
|
+
return `(function(){try{var m=document.cookie.match(/dheme-mode=(\\w+)/);var mode=m?m[1]:null;if(!mode){mode=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'${defaultMode}'}if(mode==='dark'){document.documentElement.classList.add('dark')}else{document.documentElement.classList.remove('dark')}}catch(e){}})()`;
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
applyThemeCSSVariables,
|
|
117
|
+
buildCacheKey,
|
|
118
|
+
getBlockingScriptPayload,
|
|
119
|
+
getNextBlockingScriptPayload,
|
|
120
|
+
removeThemeCSSVariables,
|
|
121
|
+
themeToCSS,
|
|
122
|
+
themeToCSSBothModes
|
|
123
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dheme/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "React bindings for Dheme SDK with zero-FOUC theme application",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.mjs",
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./utils": {
|
|
15
|
+
"types": "./dist/utils.d.ts",
|
|
16
|
+
"import": "./dist/utils.mjs",
|
|
17
|
+
"require": "./dist/utils.js"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|