@fakhrirafiki/theme-engine 0.4.7 → 0.4.8
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 +281 -115
- package/dist/index.d.mts +65 -26
- package/dist/index.d.ts +65 -26
- package/dist/index.js +84 -64
- package/dist/index.mjs +83 -64
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4265,17 +4265,10 @@ function ThemeProvider({
|
|
|
4265
4265
|
children,
|
|
4266
4266
|
defaultMode = "system",
|
|
4267
4267
|
defaultPreset,
|
|
4268
|
-
enableTransitions = true,
|
|
4269
4268
|
modeStorageKey = THEME_STORAGE_KEY,
|
|
4270
4269
|
presetStorageKey = "theme-preset",
|
|
4271
|
-
|
|
4272
|
-
customPresets,
|
|
4273
|
-
includeBuiltInPresets = true,
|
|
4274
|
-
disableScript = false,
|
|
4275
|
-
deferRenderUntilReady
|
|
4270
|
+
customPresets
|
|
4276
4271
|
}) {
|
|
4277
|
-
const shouldInjectScript = !disableScript;
|
|
4278
|
-
const shouldDeferRenderUntilReady = deferRenderUntilReady ?? disableScript;
|
|
4279
4272
|
const normalizedCustomPresets = useMemo2(() => customPresets ?? {}, [customPresets]);
|
|
4280
4273
|
const [mode, setMode] = useState(() => {
|
|
4281
4274
|
const stored = getStoredMode(modeStorageKey);
|
|
@@ -4289,9 +4282,7 @@ function ThemeProvider({
|
|
|
4289
4282
|
});
|
|
4290
4283
|
const availablePresets = useMemo2(() => {
|
|
4291
4284
|
const merged = {};
|
|
4292
|
-
|
|
4293
|
-
Object.assign(merged, tweakcnPresets);
|
|
4294
|
-
}
|
|
4285
|
+
Object.assign(merged, tweakcnPresets);
|
|
4295
4286
|
if (Object.keys(normalizedCustomPresets).length > 0) {
|
|
4296
4287
|
const validationResult = validateCustomPresets(normalizedCustomPresets);
|
|
4297
4288
|
const isDevelopment = typeof window !== "undefined" && window.location?.hostname === "localhost";
|
|
@@ -4307,8 +4298,8 @@ function ThemeProvider({
|
|
|
4307
4298
|
}
|
|
4308
4299
|
}
|
|
4309
4300
|
return merged;
|
|
4310
|
-
}, [
|
|
4311
|
-
const builtInPresets =
|
|
4301
|
+
}, [normalizedCustomPresets]);
|
|
4302
|
+
const builtInPresets = tweakcnPresets;
|
|
4312
4303
|
const getAvailablePresetById = useCallback(
|
|
4313
4304
|
(id) => {
|
|
4314
4305
|
return availablePresets[id] || null;
|
|
@@ -4316,12 +4307,8 @@ function ThemeProvider({
|
|
|
4316
4307
|
[availablePresets]
|
|
4317
4308
|
);
|
|
4318
4309
|
const [currentPreset, setCurrentPreset] = useState(null);
|
|
4319
|
-
const [isReady, setIsReady] = useState(() => !shouldDeferRenderUntilReady);
|
|
4320
4310
|
useEffect(() => {
|
|
4321
|
-
if (
|
|
4322
|
-
setIsReady(true);
|
|
4323
|
-
return;
|
|
4324
|
-
}
|
|
4311
|
+
if (typeof window === "undefined") return;
|
|
4325
4312
|
try {
|
|
4326
4313
|
const stored = localStorage.getItem(presetStorageKey);
|
|
4327
4314
|
const isDevelopment = typeof window !== "undefined" && window.location?.hostname === "localhost";
|
|
@@ -4374,10 +4361,8 @@ function ThemeProvider({
|
|
|
4374
4361
|
if (isDevelopment) {
|
|
4375
4362
|
console.warn("\u{1F3A8} UnifiedTheme: Failed to load preset from storage:", error);
|
|
4376
4363
|
}
|
|
4377
|
-
} finally {
|
|
4378
|
-
setIsReady(true);
|
|
4379
4364
|
}
|
|
4380
|
-
}, [presetStorageKey,
|
|
4365
|
+
}, [presetStorageKey, defaultPreset, getAvailablePresetById]);
|
|
4381
4366
|
useEffect(() => {
|
|
4382
4367
|
if (mode === "system") {
|
|
4383
4368
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
@@ -4456,7 +4441,7 @@ function ThemeProvider({
|
|
|
4456
4441
|
(coordinates) => {
|
|
4457
4442
|
const newMode = resolvedMode === "light" ? "dark" : "light";
|
|
4458
4443
|
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
4459
|
-
if (
|
|
4444
|
+
if (!prefersReducedMotion && typeof document !== "undefined" && "startViewTransition" in document) {
|
|
4460
4445
|
const root = document.documentElement;
|
|
4461
4446
|
if (coordinates) {
|
|
4462
4447
|
root.style.setProperty("--x", `${coordinates.x}px`);
|
|
@@ -4469,7 +4454,7 @@ function ThemeProvider({
|
|
|
4469
4454
|
handleModeChange(newMode);
|
|
4470
4455
|
}
|
|
4471
4456
|
},
|
|
4472
|
-
[resolvedMode,
|
|
4457
|
+
[resolvedMode, handleModeChange]
|
|
4473
4458
|
);
|
|
4474
4459
|
useEffect(() => {
|
|
4475
4460
|
if (!currentPreset || typeof window === "undefined") return;
|
|
@@ -4484,7 +4469,7 @@ function ThemeProvider({
|
|
|
4484
4469
|
appliedAt: Date.now()
|
|
4485
4470
|
};
|
|
4486
4471
|
setCurrentPreset(presetData);
|
|
4487
|
-
if (
|
|
4472
|
+
if (typeof window !== "undefined") {
|
|
4488
4473
|
try {
|
|
4489
4474
|
localStorage.setItem(presetStorageKey, JSON.stringify(presetData));
|
|
4490
4475
|
} catch (error) {
|
|
@@ -4495,7 +4480,7 @@ function ThemeProvider({
|
|
|
4495
4480
|
applyPresetColors(preset.colors, resolvedMode);
|
|
4496
4481
|
}
|
|
4497
4482
|
},
|
|
4498
|
-
[presetStorageKey,
|
|
4483
|
+
[presetStorageKey, applyPresetColors, resolvedMode]
|
|
4499
4484
|
);
|
|
4500
4485
|
const setThemePresetById = useCallback(
|
|
4501
4486
|
(presetId) => {
|
|
@@ -4519,53 +4504,50 @@ function ThemeProvider({
|
|
|
4519
4504
|
[getAvailablePresetById, applyPreset]
|
|
4520
4505
|
);
|
|
4521
4506
|
const clearPreset = useCallback(() => {
|
|
4522
|
-
if (
|
|
4507
|
+
if (typeof window !== "undefined") {
|
|
4523
4508
|
try {
|
|
4524
4509
|
localStorage.removeItem(presetStorageKey);
|
|
4525
4510
|
} catch (error) {
|
|
4526
4511
|
console.error("\u{1F3A8} UnifiedTheme: Failed to clear preset:", error);
|
|
4527
4512
|
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
console.warn("\u{1F3A8} UnifiedTheme: Default preset not found:", defaultPreset);
|
|
4544
|
-
setCurrentPreset(null);
|
|
4545
|
-
}
|
|
4513
|
+
}
|
|
4514
|
+
if (defaultPreset) {
|
|
4515
|
+
const preset = getAvailablePresetById(defaultPreset);
|
|
4516
|
+
if (preset) {
|
|
4517
|
+
const presetData = {
|
|
4518
|
+
presetId: defaultPreset,
|
|
4519
|
+
presetName: preset.label,
|
|
4520
|
+
colors: {
|
|
4521
|
+
light: preset.styles.light,
|
|
4522
|
+
dark: preset.styles.dark
|
|
4523
|
+
},
|
|
4524
|
+
appliedAt: Date.now()
|
|
4525
|
+
};
|
|
4526
|
+
setCurrentPreset(presetData);
|
|
4527
|
+
applyPresetColors(presetData.colors, resolvedMode);
|
|
4546
4528
|
} else {
|
|
4529
|
+
console.warn("\u{1F3A8} UnifiedTheme: Default preset not found:", defaultPreset);
|
|
4547
4530
|
setCurrentPreset(null);
|
|
4548
|
-
const root = document.documentElement;
|
|
4549
|
-
const allProperties = [
|
|
4550
|
-
...CSS_PROPERTY_CATEGORIES.colors,
|
|
4551
|
-
...CSS_PROPERTY_CATEGORIES.typography,
|
|
4552
|
-
...CSS_PROPERTY_CATEGORIES.layout,
|
|
4553
|
-
...CSS_PROPERTY_CATEGORIES.shadows,
|
|
4554
|
-
...CSS_PROPERTY_CATEGORIES.spacing
|
|
4555
|
-
];
|
|
4556
|
-
let clearedCount = 0;
|
|
4557
|
-
allProperties.forEach((prop) => {
|
|
4558
|
-
const cssVar = `--${prop}`;
|
|
4559
|
-
root.style.removeProperty(cssVar);
|
|
4560
|
-
clearedCount++;
|
|
4561
|
-
});
|
|
4562
4531
|
}
|
|
4532
|
+
} else {
|
|
4533
|
+
setCurrentPreset(null);
|
|
4534
|
+
const root = document.documentElement;
|
|
4535
|
+
const allProperties = [
|
|
4536
|
+
...CSS_PROPERTY_CATEGORIES.colors,
|
|
4537
|
+
...CSS_PROPERTY_CATEGORIES.typography,
|
|
4538
|
+
...CSS_PROPERTY_CATEGORIES.layout,
|
|
4539
|
+
...CSS_PROPERTY_CATEGORIES.shadows,
|
|
4540
|
+
...CSS_PROPERTY_CATEGORIES.spacing
|
|
4541
|
+
];
|
|
4542
|
+
let clearedCount = 0;
|
|
4543
|
+
allProperties.forEach((prop) => {
|
|
4544
|
+
const cssVar = `--${prop}`;
|
|
4545
|
+
root.style.removeProperty(cssVar);
|
|
4546
|
+
clearedCount++;
|
|
4547
|
+
});
|
|
4563
4548
|
}
|
|
4564
|
-
}, [presetStorageKey,
|
|
4565
|
-
const scriptElement =
|
|
4566
|
-
if (!isReady && shouldDeferRenderUntilReady) {
|
|
4567
|
-
return scriptElement;
|
|
4568
|
-
}
|
|
4549
|
+
}, [presetStorageKey, defaultPreset, getAvailablePresetById, applyPresetColors, resolvedMode]);
|
|
4550
|
+
const scriptElement = /* @__PURE__ */ jsx2(ThemeScript, { presetStorageKey, defaultPreset });
|
|
4569
4551
|
const isUsingDefaultPreset = !!defaultPreset && currentPreset?.presetId === defaultPreset;
|
|
4570
4552
|
const contextValue = {
|
|
4571
4553
|
mode,
|
|
@@ -4821,7 +4803,7 @@ var AnimatedRow = ({
|
|
|
4821
4803
|
}) => {
|
|
4822
4804
|
if (presets.length === 0) return null;
|
|
4823
4805
|
const duplicatedPresets = Array(animation.duplicationFactor).fill(presets).flat();
|
|
4824
|
-
const totalWidth = presets.reduce((sum, preset) => sum + (Number(preset.metadata?.buttonWidth) || layout.buttonWidth), 0) + presets.length * layout.buttonGap;
|
|
4806
|
+
const totalWidth = presets.reduce((sum, preset) => sum + (Number(preset.metadata?.buttonWidth) || layout.buttonWidth), 0) + Math.max(0, presets.length - 1) * layout.buttonGap;
|
|
4825
4807
|
const effectiveScrollSpeed = Math.max(0.1, animation.scrollSpeed || 1);
|
|
4826
4808
|
const animationDuration = presets.length * animation.duration / effectiveScrollSpeed;
|
|
4827
4809
|
return /* @__PURE__ */ jsx4(
|
|
@@ -5018,6 +5000,42 @@ function useTypedTheme(customPresets) {
|
|
|
5018
5000
|
setThemePresetById
|
|
5019
5001
|
};
|
|
5020
5002
|
}
|
|
5003
|
+
|
|
5004
|
+
// src/hooks/useThemeEngine.ts
|
|
5005
|
+
function useThemeEngine() {
|
|
5006
|
+
const theme = useTheme();
|
|
5007
|
+
const darkMode = theme.resolvedMode === "dark";
|
|
5008
|
+
const setDarkMode = (mode) => theme.setMode(mode);
|
|
5009
|
+
const toggleDarkMode = (coordinates) => theme.toggleMode(coordinates);
|
|
5010
|
+
const applyThemeById = (themeId) => theme.setThemePresetById(themeId);
|
|
5011
|
+
const applyPresetById = applyThemeById;
|
|
5012
|
+
const clearTheme = () => theme.clearPreset();
|
|
5013
|
+
const clearPreset = clearTheme;
|
|
5014
|
+
const currentTheme = theme.currentPreset;
|
|
5015
|
+
const currentPreset = theme.currentPreset;
|
|
5016
|
+
return {
|
|
5017
|
+
// Mode
|
|
5018
|
+
darkMode,
|
|
5019
|
+
mode: theme.mode,
|
|
5020
|
+
resolvedMode: theme.resolvedMode,
|
|
5021
|
+
setDarkMode,
|
|
5022
|
+
setMode: theme.setMode,
|
|
5023
|
+
toggleDarkMode,
|
|
5024
|
+
toggleMode: theme.toggleMode,
|
|
5025
|
+
// Presets (theme naming)
|
|
5026
|
+
applyThemeById,
|
|
5027
|
+
applyPresetById,
|
|
5028
|
+
clearTheme,
|
|
5029
|
+
clearPreset,
|
|
5030
|
+
currentTheme,
|
|
5031
|
+
currentPreset,
|
|
5032
|
+
// Advanced / diagnostics
|
|
5033
|
+
isUsingDefaultPreset: theme.isUsingDefaultPreset,
|
|
5034
|
+
availablePresets: theme.availablePresets,
|
|
5035
|
+
builtInPresets: theme.builtInPresets,
|
|
5036
|
+
customPresets: theme.customPresets
|
|
5037
|
+
};
|
|
5038
|
+
}
|
|
5021
5039
|
export {
|
|
5022
5040
|
ThemePresetButtons,
|
|
5023
5041
|
ThemeProvider,
|
|
@@ -5034,6 +5052,7 @@ export {
|
|
|
5034
5052
|
searchPresets,
|
|
5035
5053
|
tweakcnPresets,
|
|
5036
5054
|
useTheme,
|
|
5055
|
+
useThemeEngine,
|
|
5037
5056
|
useTypedTheme,
|
|
5038
5057
|
validateCustomPresets,
|
|
5039
5058
|
validateTweakCNPreset,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fakhrirafiki/theme-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Elegant theming system with smooth transitions, custom presets, semantic accent colors, and complete shadcn/ui support for modern React applications",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|