react-theme-snap
Version:
A lightweight React package to easily add dark mode support with theme persistence, custom tokens. Plug-and-play with built-in context, hook — fully customizable for your UI.
298 lines (280 loc) • 10 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
ThemeContext: () => ThemeContext,
ThemeProvider: () => ThemeProvider,
ThemeToggle: () => ThemeToggle,
ThemedComponent: () => ThemedComponent,
ThemedComponentSync: () => ThemedComponentSync,
useDarkTheme: () => useDarkTheme
});
module.exports = __toCommonJS(index_exports);
// src/components/ThemeToggleBtn.tsx
var import_clsx = __toESM(require("clsx"));
// ../node_modules/lucide-react/dist/esm/createLucideIcon.js
var import_react2 = require("react");
// ../node_modules/lucide-react/dist/esm/shared/src/utils.js
var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
var toCamelCase = (string) => string.replace(
/^([A-Z])|[\s-_]+(\w)/g,
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
);
var toPascalCase = (string) => {
const camelCase = toCamelCase(string);
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
};
var mergeClasses = (...classes) => classes.filter((className, index, array) => {
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
}).join(" ").trim();
var hasA11yProp = (props) => {
for (const prop in props) {
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
return true;
}
}
};
// ../node_modules/lucide-react/dist/esm/Icon.js
var import_react = require("react");
// ../node_modules/lucide-react/dist/esm/defaultAttributes.js
var defaultAttributes = {
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: 2,
strokeLinecap: "round",
strokeLinejoin: "round"
};
// ../node_modules/lucide-react/dist/esm/Icon.js
var Icon = (0, import_react.forwardRef)(
({
color = "currentColor",
size = 24,
strokeWidth = 2,
absoluteStrokeWidth,
className = "",
children,
iconNode,
...rest
}, ref) => (0, import_react.createElement)(
"svg",
{
ref,
...defaultAttributes,
width: size,
height: size,
stroke: color,
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
className: mergeClasses("lucide", className),
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
...rest
},
[
...iconNode.map(([tag, attrs]) => (0, import_react.createElement)(tag, attrs)),
...Array.isArray(children) ? children : [children]
]
)
);
// ../node_modules/lucide-react/dist/esm/createLucideIcon.js
var createLucideIcon = (iconName, iconNode) => {
const Component = (0, import_react2.forwardRef)(
({ className, ...props }, ref) => (0, import_react2.createElement)(Icon, {
ref,
iconNode,
className: mergeClasses(
`lucide-${toKebabCase(toPascalCase(iconName))}`,
`lucide-${iconName}`,
className
),
...props
})
);
Component.displayName = toPascalCase(iconName);
return Component;
};
// ../node_modules/lucide-react/dist/esm/icons/moon.js
var __iconNode = [
[
"path",
{
d: "M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",
key: "kfwtm"
}
]
];
var Moon = createLucideIcon("moon", __iconNode);
// ../node_modules/lucide-react/dist/esm/icons/sun.js
var __iconNode2 = [
["circle", { cx: "12", cy: "12", r: "4", key: "4exip2" }],
["path", { d: "M12 2v2", key: "tus03m" }],
["path", { d: "M12 20v2", key: "1lh1kg" }],
["path", { d: "m4.93 4.93 1.41 1.41", key: "149t6j" }],
["path", { d: "m17.66 17.66 1.41 1.41", key: "ptbguv" }],
["path", { d: "M2 12h2", key: "1t8f8n" }],
["path", { d: "M20 12h2", key: "1q8mjw" }],
["path", { d: "m6.34 17.66-1.41 1.41", key: "1m8zz5" }],
["path", { d: "m19.07 4.93-1.41 1.41", key: "1shlcs" }]
];
var Sun = createLucideIcon("sun", __iconNode2);
// src/components/ThemeToggleBtn.tsx
var import_jsx_runtime = require("react/jsx-runtime");
var ThemeToggle = ({
isDark,
toggleTheme,
iconSize,
className
}) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
onClick: toggleTheme,
className: (0, import_clsx.default)("p-2 rounded-md transition cursor-pointer", className),
"aria-label": "Toggle theme",
children: isDark ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Sun, { size: iconSize }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Moon, { size: iconSize })
}
);
// src/components/ThemedComponent.tsx
var import_react3 = require("react");
var import_jsx_runtime2 = require("react/jsx-runtime");
var ThemedComponent = ({
defaultMode = "inherit",
tokens,
children
}) => {
const [isDark, setIsDark] = (0, import_react3.useState)(() => {
if (defaultMode === "inherit")
return document.documentElement.classList.contains("dark");
return defaultMode === "dark";
});
const toggleTheme = () => setIsDark((prev) => !prev);
const themeClasses = isDark ? tokens?.dark || {} : tokens?.light || {};
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: children({ isDark, toggleTheme, themeClasses }) });
};
// src/components/ThemedComponentSync.tsx
var import_react5 = require("react");
// src/hooks/useDarkTheme.tsx
var import_react4 = require("react");
var ThemeContext = (0, import_react4.createContext)(null);
var useDarkTheme = () => {
const context = (0, import_react4.useContext)(ThemeContext);
if (!context)
throw new Error("UseDarkTheme Hook was used outside of the ThemeProvider");
return context;
};
// src/components/ThemedComponentSync.tsx
var import_jsx_runtime3 = require("react/jsx-runtime");
var ThemedComponentSync = ({
defaultMode = "inherit",
tokens,
children
}) => {
const globalTheme = useDarkTheme();
const [isDark, setIsDark] = (0, import_react5.useState)(() => {
if (defaultMode === "inherit") return globalTheme.isDark;
if (defaultMode === "inherit-reverse") return !globalTheme.isDark;
return defaultMode === "dark";
});
const toggleTheme = () => setIsDark((prev) => !prev);
const themeClasses = isDark ? tokens?.dark || globalTheme.themeClasses : tokens?.light || globalTheme.themeClasses;
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: children({ isDark, toggleTheme, themeClasses }) });
};
// src/context/ThemeContext.tsx
var import_react6 = require("react");
var import_jsx_runtime4 = require("react/jsx-runtime");
var ThemeProvider = ({
children,
tokens,
storageKey = "is-dark"
}) => {
const [isDark, setIsDark] = (0, import_react6.useState)(() => {
const saved = localStorage.getItem(storageKey);
return saved ? JSON.parse(saved) : false;
});
(0, import_react6.useEffect)(() => {
const systemDefaultTheme = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (localStorage.getItem(storageKey) === null) {
setIsDark(systemDefaultTheme);
}
document.documentElement.classList.toggle("dark", isDark);
localStorage.setItem(storageKey, JSON.stringify(isDark));
document.documentElement.classList.add("theme-transition");
const timeout = setTimeout(() => {
document.documentElement.classList.remove("theme-transition");
}, 300);
return () => clearTimeout(timeout);
}, [isDark, storageKey]);
const toggleTheme = () => setIsDark((prev) => !prev);
if (!tokens.dark) {
throw new Error("Dark object not definded");
}
if (!tokens.light) {
throw new Error("Light object not definded");
}
const themeClasses = isDark ? tokens.dark : tokens.light;
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
ThemeContext.Provider,
{
value: {
isDark,
toggleTheme,
themeClasses
},
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children })
}
);
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ThemeContext,
ThemeProvider,
ThemeToggle,
ThemedComponent,
ThemedComponentSync,
useDarkTheme
});
/*! Bundled license information:
lucide-react/dist/esm/shared/src/utils.js:
lucide-react/dist/esm/defaultAttributes.js:
lucide-react/dist/esm/Icon.js:
lucide-react/dist/esm/createLucideIcon.js:
lucide-react/dist/esm/icons/moon.js:
lucide-react/dist/esm/icons/sun.js:
lucide-react/dist/esm/lucide-react.js:
(**
* @license lucide-react v0.536.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*)
*/