UNPKG

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
"use strict"; 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. *) */