🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

cssfun

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cssfun - npm Package Compare versions

Comparing version
0.0.13
to
0.0.14
+34
-13
dist/cssfun.js

@@ -464,14 +464,35 @@ (function (global, factory) {

const makeCssVars = (theme = {}, prefix = '--') => {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
if (isObject(value)) {
Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));
} else if (typeof value !== 'undefined' && value !== null) {
acc[`${prefix}-${key}`] = value;
}
return acc;
}, {});
/**
* Flattens a nested theme object into a map of CSS variable names to values.
* Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).
* @private
* @param {Object} [theme={}] - Nested theme object.
* @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.
* @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.
*/
const makeCssVars = (theme = {}, prefix) => {
function build(theme, nameAcc) {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;
if (isObject(value)) {
Object.assign(acc, build(value, name));
} else if (typeof value !== 'undefined' && value !== null) {
acc[name] = value;
}
return acc;
}, {});
}
return build(theme);
};
/**
* Returns keys that differ between two objects, with each side’s value.
* @private
* @param {Object} left - First object.
* @param {Object} right - Second object.
* @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.
*/
const getDiff = (left, right) => {

@@ -512,4 +533,4 @@ return Object.keys(left).reduce((acc, key) => {

*
* @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`.
* For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.
* @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.
* Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).
*

@@ -560,3 +581,3 @@ * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance.

const colorScheme = options.colorScheme || 'light dark';
const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;
const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;

@@ -563,0 +584,0 @@ let styles;

@@ -1,2 +0,2 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).CSSFUN={})}(this,(function(e){"use strict";const t=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),s=["prefix","generateUid","generateClassName","shouldAttachToDOM","attributes","renderers"];class r{constructor(e,t={}){this.styles=e,this.classes={},s.forEach((e=>{e in t&&(this[e]=t[e])})),this.renderers||(this.renderers=[this.renderStyles,this.parseStyles]),this.prefix||(this.prefix=r.prefix),this.uid=this.generateUid();let i=0;Object.keys(e).forEach((e=>{e.match(r.classRegex)&&(this.classes[e]=this.generateClassName(e,++i))}))}generateUid(){const e=JSON.stringify(this.styles);let t=2166136261;for(let s=0;s<e.length;s++)t^=e.charCodeAt(s),t=16777619*t>>>0;return t.toString(36)}generateClassName(e,t){return`${this.prefix[0]}-${this.uid}-${t}`}render(){const e=this.renderers.map((e=>("string"==typeof e?this[e]:e).bind(this)));return e.reduce(((e,t)=>(...s)=>e(t(...s))))(this.styles)}renderStyles(e,s=1){return Object.keys(e).reduce(((r,i)=>{const n=e[i];if(t(n)){if(Object.keys(n).length>0){const e=this.renderStyles(n,s+1);r.push(`${i}{${e}}`)}}else null!=n&&r.push(`${i}:${n};`);return r}),[]).join("")}parseStyles(e,s,i,n){const l=e=>e in this.classes?`.${this.classes[e]}`:e,c=e=>n&&i?`${i} ${e}`:e.match(r.globalPrefixRegex)?`${i?`${i} `:""}${e.replace(r.globalPrefixRegex,"")}`:l(e).replace(r.referenceRegex,((e,t)=>l(t))).replace(r.nestedRegex,i);return Object.keys(e).reduce(((n,l)=>{const h=e[l];if(t(h))if(l.match(r.globalRegex))Object.assign(s||n,this.parseStyles(h,n,i,!0));else if((l.match(r.nestedRegex)||l.match(r.globalPrefixRegex))&&s){const e=c(l);s[e]={},Object.assign(s[e],this.parseStyles(h,s,e))}else{const e=c(l);n[e]={};const t=e.match(/@/)?[]:[n,e];Object.assign(n[e],this.parseStyles(h,...t))}else null!=h&&(n[l.match(/-/)?l:(o=l,o.replace(/([A-Z])/g,(e=>`-${e[0].toLowerCase()}`)))]=h);var o;return n}),{})}getAttributes(){const e=Object.assign({},this.attributes);return e[`data-${this.prefix}-uid`]=this.uid,e}toString(){const e=this.getAttributes();return`<style${Object.keys(e).map((t=>` ${t}="${e[t]}"`)).join("")}>${this.render()}</style>`}shouldAttachToDOM(){return"undefined"!=typeof document&&!document.querySelector(`style[data-${this.prefix}-uid="${this.uid}"]`)}attach(){if(r.registry.some((({uid:e})=>e===this.uid))||r.registry.push(this),this.shouldAttachToDOM()){this.el=document.createElement("style");const e=this.getAttributes();Object.keys(e).forEach((t=>{this.el.setAttribute(t,e[t])})),this.el.textContent=this.render(),document.head.appendChild(this.el)}return this}destroy(){const e=r.registry.indexOf(this);return e>-1&&r.registry.splice(e,1),this.el&&(this.el.parentNode&&this.el.parentNode.removeChild(this.el),this.el=null),this}static toString(){return r.registry.join("")}static toCSS(){return r.registry.map((e=>e.render())).join("")}static destroy(){r.registry.slice().forEach((e=>e.destroy()))}}r.classRegex=/^\w+$/,r.globalRegex=/^@global$/,r.globalPrefixRegex=/^@global\s+/,r.referenceRegex=/\$(\w+)/g,r.nestedRegex=/&/g,r.prefix="fun",r.indent=" ",r.registry=[],r.debug=!1;const i=(e,t)=>new r(e,t).attach(),n=(e={},s="--")=>Object.keys(e).reduce(((r,i)=>{const l=e[i];return t(l)?Object.assign(r,n(l,`${s}-${i}`)):null!=l&&(r[`${s}-${i}`]=l),r}),{});e.StyleSheet=r,e.createTheme=(e={},t={})=>{const s=t.colorScheme||"light dark",l=`--${t.cssVarsPrefix||r.prefix}`;let c;if("light dark"===s){const t={light:n(e.light,l),dark:n(e.dark,l)},s=(h=t.light,o=t.dark,Object.keys(h).reduce(((e,t)=>(h[t]!==o[t]&&(e.left[t]=h[t],e.right[t]=o[t]),e)),{left:{},right:{}}));c={root:{":where(&)":Object.assign({colorScheme:"light"},t.light),':where([data-color-scheme="dark"] &)':Object.assign({colorScheme:"dark"},s.right)},"@media (prefers-color-scheme: dark)":{":where($root)":Object.assign({colorScheme:"dark"},s.right),':where([data-color-scheme="light"] $root)':Object.assign({colorScheme:"light"},s.left)}}}else c={root:{":where(&)":Object.assign({colorScheme:s},n(e[s],l))}};var h,o;return(t.createStyleSheet||i)(c,t.styleSheetOptions)},e.css=i}));
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).CSSFUN={})}(this,function(e){"use strict";const t=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),s=["prefix","generateUid","generateClassName","shouldAttachToDOM","attributes","renderers"];class r{constructor(e,t={}){this.styles=e,this.classes={},s.forEach(e=>{e in t&&(this[e]=t[e])}),this.renderers||(this.renderers=[this.renderStyles,this.parseStyles]),this.prefix||(this.prefix=r.prefix),this.uid=this.generateUid();let i=0;Object.keys(e).forEach(e=>{e.match(r.classRegex)&&(this.classes[e]=this.generateClassName(e,++i))})}generateUid(){const e=JSON.stringify(this.styles);let t=2166136261;for(let s=0;s<e.length;s++)t^=e.charCodeAt(s),t=16777619*t>>>0;return t.toString(36)}generateClassName(e,t){return`${this.prefix[0]}-${this.uid}-${t}`}render(){const e=this.renderers.map(e=>("string"==typeof e?this[e]:e).bind(this));return e.reduce((e,t)=>(...s)=>e(t(...s)))(this.styles)}renderStyles(e,s=1){return Object.keys(e).reduce((r,i)=>{const n=e[i];if(t(n)){if(Object.keys(n).length>0){const e=this.renderStyles(n,s+1);r.push(`${i}{${e}}`)}}else null!=n&&r.push(`${i}:${n};`);return r},[]).join("")}parseStyles(e,s,i,n){const c=e=>e in this.classes?`.${this.classes[e]}`:e,l=e=>n&&i?`${i} ${e}`:e.match(r.globalPrefixRegex)?`${i?`${i} `:""}${e.replace(r.globalPrefixRegex,"")}`:c(e).replace(r.referenceRegex,(e,t)=>c(t)).replace(r.nestedRegex,i);return Object.keys(e).reduce((n,c)=>{const h=e[c];if(t(h))if(c.match(r.globalRegex))Object.assign(s||n,this.parseStyles(h,n,i,!0));else if((c.match(r.nestedRegex)||c.match(r.globalPrefixRegex))&&s){const e=l(c);s[e]={},Object.assign(s[e],this.parseStyles(h,s,e))}else{const e=l(c);n[e]={};const t=e.match(/@/)?[]:[n,e];Object.assign(n[e],this.parseStyles(h,...t))}else null!=h&&(n[c.match(/-/)?c:(o=c,o.replace(/([A-Z])/g,e=>`-${e[0].toLowerCase()}`))]=h);var o;return n},{})}getAttributes(){const e=Object.assign({},this.attributes);return e[`data-${this.prefix}-uid`]=this.uid,e}toString(){const e=this.getAttributes();return`<style${Object.keys(e).map(t=>` ${t}="${e[t]}"`).join("")}>${this.render()}</style>`}shouldAttachToDOM(){return"undefined"!=typeof document&&!document.querySelector(`style[data-${this.prefix}-uid="${this.uid}"]`)}attach(){if(r.registry.some(({uid:e})=>e===this.uid)||r.registry.push(this),this.shouldAttachToDOM()){this.el=document.createElement("style");const e=this.getAttributes();Object.keys(e).forEach(t=>{this.el.setAttribute(t,e[t])}),this.el.textContent=this.render(),document.head.appendChild(this.el)}return this}destroy(){const e=r.registry.indexOf(this);return e>-1&&r.registry.splice(e,1),this.el&&(this.el.parentNode&&this.el.parentNode.removeChild(this.el),this.el=null),this}static toString(){return r.registry.join("")}static toCSS(){return r.registry.map(e=>e.render()).join("")}static destroy(){r.registry.slice().forEach(e=>e.destroy())}}r.classRegex=/^\w+$/,r.globalRegex=/^@global$/,r.globalPrefixRegex=/^@global\s+/,r.referenceRegex=/\$(\w+)/g,r.nestedRegex=/&/g,r.prefix="fun",r.indent=" ",r.registry=[],r.debug=!1;const i=(e,t)=>new r(e,t).attach(),n=(e={},s)=>function e(r,i){return Object.keys(r).reduce((n,c)=>{const l=r[c],h=i?`${i}-${c}`:s?`--${s}-${c}`:`--${c}`;return t(l)?Object.assign(n,e(l,h)):null!=l&&(n[h]=l),n},{})}(e);e.StyleSheet=r,e.createTheme=(e={},t={})=>{const s=t.colorScheme||"light dark",c="cssVarsPrefix"in t?t.cssVarsPrefix:r.prefix;let l;if("light dark"===s){const t={light:n(e.light,c),dark:n(e.dark,c)},s=(h=t.light,o=t.dark,Object.keys(h).reduce((e,t)=>(h[t]!==o[t]&&(e.left[t]=h[t],e.right[t]=o[t]),e),{left:{},right:{}}));l={root:{":where(&)":Object.assign({colorScheme:"light"},t.light),':where([data-color-scheme="dark"] &)':Object.assign({colorScheme:"dark"},s.right)},"@media (prefers-color-scheme: dark)":{":where($root)":Object.assign({colorScheme:"dark"},s.right),':where([data-color-scheme="light"] $root)':Object.assign({colorScheme:"light"},s.left)}}}else l={root:{":where(&)":Object.assign({colorScheme:s},n(e[s],c))}};var h,o;return(t.createStyleSheet||i)(l,t.styleSheetOptions)},e.css=i});
//# sourceMappingURL=cssfun.min.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"cssfun.min.js","sources":["../src/utils/isObject.js","../src/StyleSheet.js","../src/utils/dev.js","../src/css.js","../src/createTheme.js"],"sourcesContent":["/**\n * Check if a value is an object.\n * @param {any} value - The value to check.\n * @returns {boolean} True if the value is an object, false otherwise.\n * @module\n * @private\n */\nconst isObject = value =>\n value !== null && typeof value === 'object' && !Array.isArray(value);\n\nexport default isObject;\n","import isObject from './utils/isObject.js';\nimport __DEV__ from './utils/dev.js';\n\nconst camelizedToDashed = str => str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);\nconst compose = fns => fns.reduce((f, g) => (...args) => f(g(...args)));\n\nconst styleSheetOptions = ['prefix', 'generateUid', 'generateClassName', 'shouldAttachToDOM', 'attributes', 'renderers'];\n\n/**\n * The StyleSheet class is responsible for creating and managing a CSS stylesheet.\n * It takes a styles object and an optional options object as input, processes the styles, \n * and generates a CSS stylesheet that can be attached to the DOM, destroyed, or \n * rendered as a string for server-side rendering.\n * \n * @module\n * @class\n * @param {Object} styles - The styles object. This is an object where keys represent \n * CSS selectors and values are style objects. The styles object is processed through \n * the renderers to generate the final CSS string. It is stored in the instance as `this.styles`.\n * @param {Object} [options={}] - Configuration options. The following options are assigned to the instance (`this`):\n * `prefix`, `generateUid`, `generateClassName`, `shouldAttachToDOM`, `attributes`, `renderers`.\n * @param {String} [options.prefix='fun'] - Prefix for generating unique identifiers and data attributes.\n * @param {Function} [options.generateUid] - Custom function to generate the unique identifier.\n * @param {Function} [options.generateClassName] - Custom function to generate unique class names.\n * @param {Object} [options.attributes] - Attributes to be added to the `<style>` element.\n * @param {Array} [options.renderers=['parseStyles', 'renderStyles']] - Array of renderer functions or method names.\n * Renderers are composed in sequence. Strings or functions are automatically bound to `this`.\n * @param {Function} [options.shouldAttachToDOM] - Custom function to determine whether the StyleSheet should be added to the DOM.\n * \n * @example\n * // Create a new StyleSheet instance with a styles object.\n * const instance = new StyleSheet({\n * root: {\n * color: 'black'\n * }\n * });\n * \n * // Attach the StyleSheet instance to the DOM.\n * instance.attach();\n * \n * // Retrieve the generated classes object from the instance.\n * const { classes } = instance;\n * \n * // Use the generated class name in your component.\n * function Header() {\n * return <h1 className={classes.root}>Hello World</h1>;\n * }\n * \n * @property {Object} classes - Object mapping original class names to generated unique class names.\n * @property {Object} styles - The original styles object provided to the instance.\n * @property {String} uid - Unique identifier for the StyleSheet instance, generated using `this.generateUid`.\n * @property {String} prefix - Prefix for generating unique identifiers. Set via options or subclass.\n * @property {Object} attributes - Attributes to be added to the `<style>` element. Set via options or subclass.\n * @property {Array} renderers - Array of renderer functions or method names used to process the styles object. Set via options or subclass.\n * @property {HTMLElement} el - Reference to the `<style>` element in the DOM. Created when the instance is attached to the DOM.\n */\nclass StyleSheet {\n constructor(styles, options = {}) {\n // Styles object.\n this.styles = styles;\n // Original class names object.\n this.classes = {};\n // Set options on the instance.\n styleSheetOptions.forEach(key => {\n if (key in options) this[key] = options[key];\n });\n // Set default renderers.\n if (!this.renderers) this.renderers = [this.renderStyles, this.parseStyles];\n // Set default prefix.\n if (!this.prefix) this.prefix = StyleSheet.prefix;\n // Generate the `StyleSheet` unique identifier.\n this.uid = this.generateUid();\n // Generate class names. Only generate class names for top-level selectors.\n let counter = 0;\n Object.keys(styles).forEach(selector => {\n if (selector.match(StyleSheet.classRegex)) {\n this.classes[selector] = this.generateClassName(selector, ++counter);\n }\n });\n }\n\n /**\n * Generate a stable unique identifier.\n * May be overridden by `options.generateUid`.\n * @returns {String} The unique identifier.\n */\n generateUid() {\n const styles = JSON.stringify(this.styles);\n // FNV-1a 32-bit offset basis.\n let hash = 2166136261;\n for (let i = 0; i < styles.length; i++) {\n // XOR with the byte value.\n hash ^= styles.charCodeAt(i);\n // Multiply by FNV prime and ensure 32-bit unsigned integer.\n hash = (hash * 16777619) >>> 0;\n }\n // Convert the hash to a shorter base-36 string.\n return hash.toString(36);\n }\n\n /**\n * Generate a unique class name.\n * Transform local selectors that are classes to unique class names\n * to be used as class names in the styles object.\n * May be overridden by `options.generateClassName` or by extending the class.\n * @param {String} className - The class name.\n * @param {Number} index - The index of the class name.\n * @returns {String} The unique class name.\n */\n generateClassName(className, index) {\n return __DEV__ && StyleSheet.debug ?\n `${this.prefix}-${this.uid}-${className}` :\n `${this.prefix[0]}-${this.uid}-${index}`;\n }\n\n /**\n * Apply the renderers to the styles object.\n * It will return a string ready to be added to the style element.\n * @returns {String} The styles object as a string.\n */\n render() {\n const renderers = this.renderers.map(\n renderer => (typeof renderer === 'string' ? this[renderer] : renderer).bind(this)\n );\n\n return compose(renderers)(this.styles);\n }\n\n /**\n * Render the styles object as a string.\n * Its one of the default renderers.\n * It will return a string ready to be added to the `style` element.\n * @param {Object} styles - The styles object.\n * @param {Number} level - The level of indentation. Used for debugging.\n * @returns {String} The styles object as a string.\n * @private\n */\n renderStyles(styles, level = 1) {\n return Object.keys(styles).reduce((acc, key) => {\n const value = styles[key];\n let indent = '', nl = '', whitespace = '';\n // Format the CSS string.\n if (__DEV__ && StyleSheet.debug) {\n indent = StyleSheet.indent.repeat(level);\n nl = '\\n';\n whitespace = ' ';\n }\n // Add the styles to the accumulator recursively.\n if (isObject(value)) {\n if (Object.keys(value).length > 0) {\n const renderedStyles = this.renderStyles(value, level + 1);\n // Add rules to the accumulator.\n acc.push(`${indent}${key}${whitespace}{${nl}${renderedStyles}${indent}}${nl}`);\n }\n } else if (typeof value !== 'undefined' && value !== null) {\n // Add the style to the accumulator.\n acc.push(`${indent}${key}:${whitespace}${value};${nl}`);\n }\n\n return acc;\n }, []).join('');\n }\n\n /**\n * Parse the styles object and transform it. \n * Expand nested styles, parse global styles, generate selectors, replace selector references \n * and convert camelized keys to dashed-case.\n * Its one of the default renderers.\n * It will return an object ready to be rendered as string by `renderStyles`.\n * @param {Object} styles - The styles object.\n * @param {Object} parent - The parent object. Used for nested styles.\n * @param {String} parentSelector - The parent selector. Used for nested styles.\n * @param {Boolean} isGlobal - If true, the styles are global styles.\n * @returns {Object} The styles object.\n * @private\n */\n parseStyles(styles, parent, parentSelector, isGlobal) {\n const fromClasses = selector => selector in this.classes ? `.${this.classes[selector]}` : selector;\n // Parse the key and generate a selector.\n const generateKey = key => {\n if (isGlobal && parentSelector) {\n // Nested global selectors.\n return `${parentSelector} ${key}`;\n }\n if (key.match(StyleSheet.globalPrefixRegex)) {\n // Global prefix and nested global prefix.\n return `${parentSelector ? `${parentSelector} ` : ''}${key.replace(StyleSheet.globalPrefixRegex, '')}`;\n }\n // Nested, references and replace class names with created ones.\n return fromClasses(key)\n .replace(StyleSheet.referenceRegex, (match, ref) => fromClasses(ref))\n .replace(StyleSheet.nestedRegex, parentSelector);\n };\n\n const result = Object.keys(styles).reduce((acc, key) => {\n const value = styles[key];\n // Parse styles recursively.\n if (isObject(value)) {\n if (key.match(StyleSheet.globalRegex)) {\n // Global and nested global styles.\n Object.assign(parent || acc, this.parseStyles(value, acc, parentSelector, true));\n } else if ((key.match(StyleSheet.nestedRegex) || key.match(StyleSheet.globalPrefixRegex)) && parent) {\n const selector = generateKey(key);\n parent[selector] = {};\n // Nested global prefix and nested styles with reference.\n Object.assign(parent[selector], this.parseStyles(value, parent, selector));\n } else {\n const selector = generateKey(key);\n acc[selector] = {};\n // Don't expand at-rules.\n const args = selector.match(/@/) ? [] : [acc, selector];\n // Regular styles.\n Object.assign(acc[selector], this.parseStyles(value, ...args));\n }\n } else if (typeof value !== 'undefined' && value !== null) {\n // Add style rules.\n // Convert camelCase to dashed-case.\n // Only convert if the key doesn't already contain a dash.\n // Allows css vars to contain camelCase parts between dashes.\n acc[key.match(/-/) ? key : camelizedToDashed(key)] = value;\n }\n\n return acc;\n }, {});\n\n return result;\n }\n\n /**\n * Get the attributes object.\n * The attributes object will be used to set the attributes on the style element.\n * The attributes object will be merged with the `this.attributes` object.\n * The `data-fun-uid` attribute will be added to the attributes object.\n * @returns {Object} The attributes object.\n * @private\n */\n getAttributes() {\n const attributes = Object.assign({}, this.attributes);\n attributes[`data-${this.prefix}-uid`] = this.uid;\n return attributes;\n }\n\n /**\n * Render the StyleSheet as a style element string.\n * Used for server-side rendering.\n * @returns {String} The instance as a string.\n */\n toString() {\n const attributes = this.getAttributes();\n const attributesHtml = Object.keys(attributes).map(key => ` ${key}=\"${attributes[key]}\"`).join('');\n const nl = (__DEV__ && StyleSheet.debug) ? '\\n' : '';\n return `<style${attributesHtml}>${nl}${this.render()}</style>${nl}`;\n }\n\n /**\n * Check if the StyleSheet should be added to the DOM.\n * By default, it returns true if running in a browser environment and no style element\n * with the same `data-fun-uid` attribute exists in the DOM.\n * This prevents duplicate style elements and ensures proper behavior for server-side rendering.\n * May be overridden by `options.shouldAttachToDOM`.\n * @returns {Boolean} True if the StyleSheet should be added to the DOM, false otherwise.\n */\n shouldAttachToDOM() {\n return typeof document !== 'undefined' && !document.querySelector(`style[data-${this.prefix}-uid=\"${this.uid}\"]`);\n }\n\n /**\n * Add the instance to the registry and if we are in the browser, \n * attach it to the DOM.\n * @returns {StyleSheet} The instance.\n */\n attach() {\n // Add the instance to the registry if it's not already there.\n if (!StyleSheet.registry.some(({ uid }) => uid === this.uid)) {\n StyleSheet.registry.push(this);\n }\n // If we're in the browser and the style element doesn't exist, create it.\n if (this.shouldAttachToDOM()) {\n // Create the style element.\n this.el = document.createElement('style');\n\n const attributes = this.getAttributes();\n // Set the attributes on the style element.\n Object.keys(attributes).forEach(key => {\n this.el.setAttribute(key, attributes[key]);\n });\n // Render the styles and set the text content of the style element.\n this.el.textContent = this.render();\n // Append the style element to the head.\n document.head.appendChild(this.el);\n }\n\n return this;\n }\n\n /**\n * Destroy the instance and remove it from the registry and \n * from the DOM, if it's present.\n * @returns {StyleSheet} The instance.\n */\n destroy() {\n const index = StyleSheet.registry.indexOf(this);\n // Remove the instance from the registry.\n if (index > -1) {\n StyleSheet.registry.splice(index, 1);\n }\n\n if (this.el) {\n // Remove the style element from the DOM.\n if (this.el.parentNode) {\n this.el.parentNode.removeChild(this.el);\n }\n // Remove the reference to the style element.\n this.el = null;\n }\n\n return this;\n }\n\n /**\n * Render all instances in the registry as a string, including the style tags.\n * Can be used to insert style tags in an HTML template for server-side rendering.\n * @returns {string} All instances in the registry as a string.\n * @static\n */\n static toString() {\n return StyleSheet.registry.join('');\n }\n\n /**\n * Render all instances in the registry as CSS string.\n * Can be used to generate an external CSS file.\n * @returns {string} All instances in the registry rendered as CSS string.\n * @static\n */\n static toCSS() {\n return StyleSheet.registry.map(instance => instance.render()).join('');\n }\n\n /**\n * Destroy all instances in the registry and remove them from \n * it and from the DOM.\n * @static\n */\n static destroy() {\n StyleSheet.registry.slice().forEach(instance => instance.destroy());\n }\n}\n\n/**\n * Regular expressions to match class names.\n * @static\n * @private\n */\nStyleSheet.classRegex = /^\\w+$/;\n\n/**\n * Regular expression to match global styles.\n * @static\n * @private\n */\nStyleSheet.globalRegex = /^@global$/;\n\n/**\n * Regular expression to match global styles with a prefix.\n * @static\n * @private\n */\nStyleSheet.globalPrefixRegex = /^@global\\s+/;\n\n/**\n * Regular expression to match references to other class names.\n * @static\n * @private\n */\nStyleSheet.referenceRegex = /\\$(\\w+)/g;\n\n/**\n * Regular expression to match nested styles.\n * @static\n * @private\n */\nStyleSheet.nestedRegex = /&/g;\n\n/**\n * @static\n * @property {String} prefix - The class prefix. Used to generate unique class names.\n * @default fun\n */\nStyleSheet.prefix = 'fun';\n\n/**\n * @static\n * @property {String} indent - The indent string. Used to format text when debug is enabled. \n * @default ' '\n */\nStyleSheet.indent = ' ';\n\n/**\n * @static\n * @property {Array} registry - The registry array. StyleSheet instances \n * will be added to this array.\n */\nStyleSheet.registry = [];\n\n/**\n * @static\n * @property {Boolean} debug - The debug flag. If true, the styles will be formatted with\n * indentation and new lines.\n * @default __DEV__\n */\nStyleSheet.debug = __DEV__;\n\nexport default StyleSheet;\n","/**\n * Development mode flag.\n * This will be replaced during build:\n * - ESM/CJS: replaced with process.env.NODE_ENV !== 'production'\n * - UMD dev: replaced with true\n * - UMD prod: replaced with false\n * @type {boolean}\n * @module\n * @private\n */\nconst __DEV__ = true;\n\nexport default __DEV__;\n","import StyleSheet from './StyleSheet.js';\n\n/**\n * Creates and attaches a new StyleSheet instance to the DOM.\n * \n * @module\n * @function\n * @param {Object} styles - An object containing CSS rules. Keys represent selectors, and values represent style objects.\n * @param {Object} [options] - Optional configuration for the StyleSheet instance. Includes options like `prefix`, `renderers`, and more.\n * @returns {StyleSheet} The created StyleSheet instance. Use the `classes` property to access the generated class names.\n * \n * @example\n * // Create styles for a link component.\n * const { classes } = css({\n * link : {\n * color : 'blue',\n * '&:hover' : {\n * textDecoration : 'underline'\n * }\n * }\n * });\n * \n * // Use the generated `link` class in a component.\n * const Link = ({ label, href }) => <a className={classes.link} href={href}>{label}</a>;\n */\nconst css = (styles, options) => new StyleSheet(styles, options).attach();\n\nexport default css;\n","import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\nconst makeCssVars = (theme = {}, prefix = '--') => {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n if (isObject(value)) {\n Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[`${prefix}-${key}`] = value;\n }\n return acc;\n }, {});\n};\n\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`. \n * For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":["isObject","value","Array","isArray","styleSheetOptions","StyleSheet","constructor","styles","options","this","classes","forEach","key","renderers","renderStyles","parseStyles","prefix","uid","generateUid","counter","Object","keys","selector","match","classRegex","generateClassName","JSON","stringify","hash","i","length","charCodeAt","toString","className","index","render","map","renderer","bind","reduce","f","g","args","compose","level","acc","renderedStyles","push","join","parent","parentSelector","isGlobal","fromClasses","generateKey","globalPrefixRegex","replace","referenceRegex","ref","nestedRegex","globalRegex","assign","str","toLowerCase","getAttributes","attributes","shouldAttachToDOM","document","querySelector","attach","registry","some","el","createElement","setAttribute","textContent","head","appendChild","destroy","indexOf","splice","parentNode","removeChild","toCSS","instance","slice","indent","debug","css","makeCssVars","theme","themes","colorScheme","cssVarsPrefix","cssVars","light","dark","diff","left","right","root","createStyleSheet"],"mappings":"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"}
{"version":3,"file":"cssfun.min.js","sources":["../src/utils/isObject.js","../src/StyleSheet.js","../src/utils/dev.js","../src/css.js","../src/createTheme.js"],"sourcesContent":["/**\n * Check if a value is an object.\n * @param {any} value - The value to check.\n * @returns {boolean} True if the value is an object, false otherwise.\n * @module\n * @private\n */\nconst isObject = value =>\n value !== null && typeof value === 'object' && !Array.isArray(value);\n\nexport default isObject;\n","import isObject from './utils/isObject.js';\nimport __DEV__ from './utils/dev.js';\n\nconst camelizedToDashed = str => str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);\nconst compose = fns => fns.reduce((f, g) => (...args) => f(g(...args)));\n\nconst styleSheetOptions = ['prefix', 'generateUid', 'generateClassName', 'shouldAttachToDOM', 'attributes', 'renderers'];\n\n/**\n * The StyleSheet class is responsible for creating and managing a CSS stylesheet.\n * It takes a styles object and an optional options object as input, processes the styles, \n * and generates a CSS stylesheet that can be attached to the DOM, destroyed, or \n * rendered as a string for server-side rendering.\n * \n * @module\n * @class\n * @param {Object} styles - The styles object. This is an object where keys represent \n * CSS selectors and values are style objects. The styles object is processed through \n * the renderers to generate the final CSS string. It is stored in the instance as `this.styles`.\n * @param {Object} [options={}] - Configuration options. The following options are assigned to the instance (`this`):\n * `prefix`, `generateUid`, `generateClassName`, `shouldAttachToDOM`, `attributes`, `renderers`.\n * @param {String} [options.prefix='fun'] - Prefix for generating unique identifiers and data attributes.\n * @param {Function} [options.generateUid] - Custom function to generate the unique identifier.\n * @param {Function} [options.generateClassName] - Custom function to generate unique class names.\n * @param {Object} [options.attributes] - Attributes to be added to the `<style>` element.\n * @param {Array} [options.renderers=['parseStyles', 'renderStyles']] - Array of renderer functions or method names.\n * Renderers are composed in sequence. Strings or functions are automatically bound to `this`.\n * @param {Function} [options.shouldAttachToDOM] - Custom function to determine whether the StyleSheet should be added to the DOM.\n * \n * @example\n * // Create a new StyleSheet instance with a styles object.\n * const instance = new StyleSheet({\n * root: {\n * color: 'black'\n * }\n * });\n * \n * // Attach the StyleSheet instance to the DOM.\n * instance.attach();\n * \n * // Retrieve the generated classes object from the instance.\n * const { classes } = instance;\n * \n * // Use the generated class name in your component.\n * function Header() {\n * return <h1 className={classes.root}>Hello World</h1>;\n * }\n * \n * @property {Object} classes - Object mapping original class names to generated unique class names.\n * @property {Object} styles - The original styles object provided to the instance.\n * @property {String} uid - Unique identifier for the StyleSheet instance, generated using `this.generateUid`.\n * @property {String} prefix - Prefix for generating unique identifiers. Set via options or subclass.\n * @property {Object} attributes - Attributes to be added to the `<style>` element. Set via options or subclass.\n * @property {Array} renderers - Array of renderer functions or method names used to process the styles object. Set via options or subclass.\n * @property {HTMLElement} el - Reference to the `<style>` element in the DOM. Created when the instance is attached to the DOM.\n */\nclass StyleSheet {\n constructor(styles, options = {}) {\n // Styles object.\n this.styles = styles;\n // Original class names object.\n this.classes = {};\n // Set options on the instance.\n styleSheetOptions.forEach(key => {\n if (key in options) this[key] = options[key];\n });\n // Set default renderers.\n if (!this.renderers) this.renderers = [this.renderStyles, this.parseStyles];\n // Set default prefix.\n if (!this.prefix) this.prefix = StyleSheet.prefix;\n // Generate the `StyleSheet` unique identifier.\n this.uid = this.generateUid();\n // Generate class names. Only generate class names for top-level selectors.\n let counter = 0;\n Object.keys(styles).forEach(selector => {\n if (selector.match(StyleSheet.classRegex)) {\n this.classes[selector] = this.generateClassName(selector, ++counter);\n }\n });\n }\n\n /**\n * Generate a stable unique identifier.\n * May be overridden by `options.generateUid`.\n * @returns {String} The unique identifier.\n */\n generateUid() {\n const styles = JSON.stringify(this.styles);\n // FNV-1a 32-bit offset basis.\n let hash = 2166136261;\n for (let i = 0; i < styles.length; i++) {\n // XOR with the byte value.\n hash ^= styles.charCodeAt(i);\n // Multiply by FNV prime and ensure 32-bit unsigned integer.\n hash = (hash * 16777619) >>> 0;\n }\n // Convert the hash to a shorter base-36 string.\n return hash.toString(36);\n }\n\n /**\n * Generate a unique class name.\n * Transform local selectors that are classes to unique class names\n * to be used as class names in the styles object.\n * May be overridden by `options.generateClassName` or by extending the class.\n * @param {String} className - The class name.\n * @param {Number} index - The index of the class name.\n * @returns {String} The unique class name.\n */\n generateClassName(className, index) {\n return __DEV__ && StyleSheet.debug ?\n `${this.prefix}-${this.uid}-${className}` :\n `${this.prefix[0]}-${this.uid}-${index}`;\n }\n\n /**\n * Apply the renderers to the styles object.\n * It will return a string ready to be added to the style element.\n * @returns {String} The styles object as a string.\n */\n render() {\n const renderers = this.renderers.map(\n renderer => (typeof renderer === 'string' ? this[renderer] : renderer).bind(this)\n );\n\n return compose(renderers)(this.styles);\n }\n\n /**\n * Render the styles object as a string.\n * Its one of the default renderers.\n * It will return a string ready to be added to the `style` element.\n * @param {Object} styles - The styles object.\n * @param {Number} level - The level of indentation. Used for debugging.\n * @returns {String} The styles object as a string.\n * @private\n */\n renderStyles(styles, level = 1) {\n return Object.keys(styles).reduce((acc, key) => {\n const value = styles[key];\n let indent = '', nl = '', whitespace = '';\n // Format the CSS string.\n if (__DEV__ && StyleSheet.debug) {\n indent = StyleSheet.indent.repeat(level);\n nl = '\\n';\n whitespace = ' ';\n }\n // Add the styles to the accumulator recursively.\n if (isObject(value)) {\n if (Object.keys(value).length > 0) {\n const renderedStyles = this.renderStyles(value, level + 1);\n // Add rules to the accumulator.\n acc.push(`${indent}${key}${whitespace}{${nl}${renderedStyles}${indent}}${nl}`);\n }\n } else if (typeof value !== 'undefined' && value !== null) {\n // Add the style to the accumulator.\n acc.push(`${indent}${key}:${whitespace}${value};${nl}`);\n }\n\n return acc;\n }, []).join('');\n }\n\n /**\n * Parse the styles object and transform it. \n * Expand nested styles, parse global styles, generate selectors, replace selector references \n * and convert camelized keys to dashed-case.\n * Its one of the default renderers.\n * It will return an object ready to be rendered as string by `renderStyles`.\n * @param {Object} styles - The styles object.\n * @param {Object} parent - The parent object. Used for nested styles.\n * @param {String} parentSelector - The parent selector. Used for nested styles.\n * @param {Boolean} isGlobal - If true, the styles are global styles.\n * @returns {Object} The styles object.\n * @private\n */\n parseStyles(styles, parent, parentSelector, isGlobal) {\n const fromClasses = selector => selector in this.classes ? `.${this.classes[selector]}` : selector;\n // Parse the key and generate a selector.\n const generateKey = key => {\n if (isGlobal && parentSelector) {\n // Nested global selectors.\n return `${parentSelector} ${key}`;\n }\n if (key.match(StyleSheet.globalPrefixRegex)) {\n // Global prefix and nested global prefix.\n return `${parentSelector ? `${parentSelector} ` : ''}${key.replace(StyleSheet.globalPrefixRegex, '')}`;\n }\n // Nested, references and replace class names with created ones.\n return fromClasses(key)\n .replace(StyleSheet.referenceRegex, (match, ref) => fromClasses(ref))\n .replace(StyleSheet.nestedRegex, parentSelector);\n };\n\n const result = Object.keys(styles).reduce((acc, key) => {\n const value = styles[key];\n // Parse styles recursively.\n if (isObject(value)) {\n if (key.match(StyleSheet.globalRegex)) {\n // Global and nested global styles.\n Object.assign(parent || acc, this.parseStyles(value, acc, parentSelector, true));\n } else if ((key.match(StyleSheet.nestedRegex) || key.match(StyleSheet.globalPrefixRegex)) && parent) {\n const selector = generateKey(key);\n parent[selector] = {};\n // Nested global prefix and nested styles with reference.\n Object.assign(parent[selector], this.parseStyles(value, parent, selector));\n } else {\n const selector = generateKey(key);\n acc[selector] = {};\n // Don't expand at-rules.\n const args = selector.match(/@/) ? [] : [acc, selector];\n // Regular styles.\n Object.assign(acc[selector], this.parseStyles(value, ...args));\n }\n } else if (typeof value !== 'undefined' && value !== null) {\n // Add style rules.\n // Convert camelCase to dashed-case.\n // Only convert if the key doesn't already contain a dash.\n // Allows css vars to contain camelCase parts between dashes.\n acc[key.match(/-/) ? key : camelizedToDashed(key)] = value;\n }\n\n return acc;\n }, {});\n\n return result;\n }\n\n /**\n * Get the attributes object.\n * The attributes object will be used to set the attributes on the style element.\n * The attributes object will be merged with the `this.attributes` object.\n * The `data-fun-uid` attribute will be added to the attributes object.\n * @returns {Object} The attributes object.\n * @private\n */\n getAttributes() {\n const attributes = Object.assign({}, this.attributes);\n attributes[`data-${this.prefix}-uid`] = this.uid;\n return attributes;\n }\n\n /**\n * Render the StyleSheet as a style element string.\n * Used for server-side rendering.\n * @returns {String} The instance as a string.\n */\n toString() {\n const attributes = this.getAttributes();\n const attributesHtml = Object.keys(attributes).map(key => ` ${key}=\"${attributes[key]}\"`).join('');\n const nl = (__DEV__ && StyleSheet.debug) ? '\\n' : '';\n return `<style${attributesHtml}>${nl}${this.render()}</style>${nl}`;\n }\n\n /**\n * Check if the StyleSheet should be added to the DOM.\n * By default, it returns true if running in a browser environment and no style element\n * with the same `data-fun-uid` attribute exists in the DOM.\n * This prevents duplicate style elements and ensures proper behavior for server-side rendering.\n * May be overridden by `options.shouldAttachToDOM`.\n * @returns {Boolean} True if the StyleSheet should be added to the DOM, false otherwise.\n */\n shouldAttachToDOM() {\n return typeof document !== 'undefined' && !document.querySelector(`style[data-${this.prefix}-uid=\"${this.uid}\"]`);\n }\n\n /**\n * Add the instance to the registry and if we are in the browser, \n * attach it to the DOM.\n * @returns {StyleSheet} The instance.\n */\n attach() {\n // Add the instance to the registry if it's not already there.\n if (!StyleSheet.registry.some(({ uid }) => uid === this.uid)) {\n StyleSheet.registry.push(this);\n }\n // If we're in the browser and the style element doesn't exist, create it.\n if (this.shouldAttachToDOM()) {\n // Create the style element.\n this.el = document.createElement('style');\n\n const attributes = this.getAttributes();\n // Set the attributes on the style element.\n Object.keys(attributes).forEach(key => {\n this.el.setAttribute(key, attributes[key]);\n });\n // Render the styles and set the text content of the style element.\n this.el.textContent = this.render();\n // Append the style element to the head.\n document.head.appendChild(this.el);\n }\n\n return this;\n }\n\n /**\n * Destroy the instance and remove it from the registry and \n * from the DOM, if it's present.\n * @returns {StyleSheet} The instance.\n */\n destroy() {\n const index = StyleSheet.registry.indexOf(this);\n // Remove the instance from the registry.\n if (index > -1) {\n StyleSheet.registry.splice(index, 1);\n }\n\n if (this.el) {\n // Remove the style element from the DOM.\n if (this.el.parentNode) {\n this.el.parentNode.removeChild(this.el);\n }\n // Remove the reference to the style element.\n this.el = null;\n }\n\n return this;\n }\n\n /**\n * Render all instances in the registry as a string, including the style tags.\n * Can be used to insert style tags in an HTML template for server-side rendering.\n * @returns {string} All instances in the registry as a string.\n * @static\n */\n static toString() {\n return StyleSheet.registry.join('');\n }\n\n /**\n * Render all instances in the registry as CSS string.\n * Can be used to generate an external CSS file.\n * @returns {string} All instances in the registry rendered as CSS string.\n * @static\n */\n static toCSS() {\n return StyleSheet.registry.map(instance => instance.render()).join('');\n }\n\n /**\n * Destroy all instances in the registry and remove them from \n * it and from the DOM.\n * @static\n */\n static destroy() {\n StyleSheet.registry.slice().forEach(instance => instance.destroy());\n }\n}\n\n/**\n * Regular expressions to match class names.\n * @static\n * @private\n */\nStyleSheet.classRegex = /^\\w+$/;\n\n/**\n * Regular expression to match global styles.\n * @static\n * @private\n */\nStyleSheet.globalRegex = /^@global$/;\n\n/**\n * Regular expression to match global styles with a prefix.\n * @static\n * @private\n */\nStyleSheet.globalPrefixRegex = /^@global\\s+/;\n\n/**\n * Regular expression to match references to other class names.\n * @static\n * @private\n */\nStyleSheet.referenceRegex = /\\$(\\w+)/g;\n\n/**\n * Regular expression to match nested styles.\n * @static\n * @private\n */\nStyleSheet.nestedRegex = /&/g;\n\n/**\n * @static\n * @property {String} prefix - The class prefix. Used to generate unique class names.\n * @default fun\n */\nStyleSheet.prefix = 'fun';\n\n/**\n * @static\n * @property {String} indent - The indent string. Used to format text when debug is enabled. \n * @default ' '\n */\nStyleSheet.indent = ' ';\n\n/**\n * @static\n * @property {Array} registry - The registry array. StyleSheet instances \n * will be added to this array.\n */\nStyleSheet.registry = [];\n\n/**\n * @static\n * @property {Boolean} debug - The debug flag. If true, the styles will be formatted with\n * indentation and new lines.\n * @default __DEV__\n */\nStyleSheet.debug = __DEV__;\n\nexport default StyleSheet;\n","/**\n * Development mode flag.\n * This will be replaced during build:\n * - ESM/CJS: replaced with process.env.NODE_ENV !== 'production'\n * - UMD dev: replaced with true\n * - UMD prod: replaced with false\n * @type {boolean}\n * @module\n * @private\n */\nconst __DEV__ = true;\n\nexport default __DEV__;\n","import StyleSheet from './StyleSheet.js';\n\n/**\n * Creates and attaches a new StyleSheet instance to the DOM.\n * \n * @module\n * @function\n * @param {Object} styles - An object containing CSS rules. Keys represent selectors, and values represent style objects.\n * @param {Object} [options] - Optional configuration for the StyleSheet instance. Includes options like `prefix`, `renderers`, and more.\n * @returns {StyleSheet} The created StyleSheet instance. Use the `classes` property to access the generated class names.\n * \n * @example\n * // Create styles for a link component.\n * const { classes } = css({\n * link : {\n * color : 'blue',\n * '&:hover' : {\n * textDecoration : 'underline'\n * }\n * }\n * });\n * \n * // Use the generated `link` class in a component.\n * const Link = ({ label, href }) => <a className={classes.link} href={href}>{label}</a>;\n */\nconst css = (styles, options) => new StyleSheet(styles, options).attach();\n\nexport default css;\n","import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\n/**\n * Flattens a nested theme object into a map of CSS variable names to values.\n * Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).\n * @private\n * @param {Object} [theme={}] - Nested theme object.\n * @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.\n * @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.\n */\nconst makeCssVars = (theme = {}, prefix) => {\n function build(theme, nameAcc) {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;\n\n if (isObject(value)) {\n Object.assign(acc, build(value, name));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[name] = value;\n }\n\n return acc;\n }, {});\n }\n return build(theme);\n};\n\n/**\n * Returns keys that differ between two objects, with each side’s value.\n * @private\n * @param {Object} left - First object.\n * @param {Object} right - Second object.\n * @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.\n */\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.\n * Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":["isObject","value","Array","isArray","styleSheetOptions","StyleSheet","constructor","styles","options","this","classes","forEach","key","renderers","renderStyles","parseStyles","prefix","uid","generateUid","counter","Object","keys","selector","match","classRegex","generateClassName","JSON","stringify","hash","i","length","charCodeAt","toString","className","index","render","map","renderer","bind","reduce","f","g","args","compose","level","acc","renderedStyles","push","join","parent","parentSelector","isGlobal","fromClasses","generateKey","globalPrefixRegex","replace","referenceRegex","ref","nestedRegex","globalRegex","assign","str","toLowerCase","getAttributes","attributes","shouldAttachToDOM","document","querySelector","attach","registry","some","el","createElement","setAttribute","textContent","head","appendChild","destroy","indexOf","splice","parentNode","removeChild","toCSS","instance","slice","indent","debug","css","makeCssVars","theme","build","nameAcc","name","themes","colorScheme","cssVarsPrefix","cssVars","light","dark","diff","left","right","root","createStyleSheet"],"mappings":"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"}

@@ -6,14 +6,35 @@ import StyleSheet from './StyleSheet.js';

const makeCssVars = (theme = {}, prefix = '--') => {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
if (isObject(value)) {
Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));
} else if (typeof value !== 'undefined' && value !== null) {
acc[`${prefix}-${key}`] = value;
}
return acc;
}, {});
/**
* Flattens a nested theme object into a map of CSS variable names to values.
* Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).
* @private
* @param {Object} [theme={}] - Nested theme object.
* @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.
* @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.
*/
const makeCssVars = (theme = {}, prefix) => {
function build(theme, nameAcc) {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;
if (isObject(value)) {
Object.assign(acc, build(value, name));
} else if (typeof value !== 'undefined' && value !== null) {
acc[name] = value;
}
return acc;
}, {});
}
return build(theme);
};
/**
* Returns keys that differ between two objects, with each side’s value.
* @private
* @param {Object} left - First object.
* @param {Object} right - Second object.
* @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.
*/
const getDiff = (left, right) => {

@@ -54,4 +75,4 @@ return Object.keys(left).reduce((acc, key) => {

*
* @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`.
* For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.
* @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.
* Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).
*

@@ -102,3 +123,3 @@ * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance.

const colorScheme = options.colorScheme || 'light dark';
const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;
const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;

@@ -105,0 +126,0 @@ let styles;

@@ -1,1 +0,1 @@

{"version":3,"file":"createTheme.js","sources":["../src/createTheme.js"],"sourcesContent":["import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\nconst makeCssVars = (theme = {}, prefix = '--') => {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n if (isObject(value)) {\n Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[`${prefix}-${key}`] = value;\n }\n return acc;\n }, {});\n};\n\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`. \n * For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":[],"mappings":"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"}
{"version":3,"file":"createTheme.js","sources":["../src/createTheme.js"],"sourcesContent":["import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\n/**\n * Flattens a nested theme object into a map of CSS variable names to values.\n * Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).\n * @private\n * @param {Object} [theme={}] - Nested theme object.\n * @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.\n * @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.\n */\nconst makeCssVars = (theme = {}, prefix) => {\n function build(theme, nameAcc) {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;\n\n if (isObject(value)) {\n Object.assign(acc, build(value, name));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[name] = value;\n }\n\n return acc;\n }, {});\n }\n return build(theme);\n};\n\n/**\n * Returns keys that differ between two objects, with each side’s value.\n * @private\n * @param {Object} left - First object.\n * @param {Object} right - Second object.\n * @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.\n */\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.\n * Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":[],"mappings":"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"}

@@ -8,14 +8,35 @@ 'use strict';

const makeCssVars = (theme = {}, prefix = '--') => {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
if (utils_isObject(value)) {
Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));
} else if (typeof value !== 'undefined' && value !== null) {
acc[`${prefix}-${key}`] = value;
}
return acc;
}, {});
/**
* Flattens a nested theme object into a map of CSS variable names to values.
* Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).
* @private
* @param {Object} [theme={}] - Nested theme object.
* @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.
* @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.
*/
const makeCssVars = (theme = {}, prefix) => {
function build(theme, nameAcc) {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;
if (utils_isObject(value)) {
Object.assign(acc, build(value, name));
} else if (typeof value !== 'undefined' && value !== null) {
acc[name] = value;
}
return acc;
}, {});
}
return build(theme);
};
/**
* Returns keys that differ between two objects, with each side’s value.
* @private
* @param {Object} left - First object.
* @param {Object} right - Second object.
* @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.
*/
const getDiff = (left, right) => {

@@ -56,4 +77,4 @@ return Object.keys(left).reduce((acc, key) => {

*
* @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`.
* For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.
* @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.
* Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).
*

@@ -104,3 +125,3 @@ * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance.

const colorScheme = options.colorScheme || 'light dark';
const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;
const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;

@@ -107,0 +128,0 @@ let styles;

@@ -1,1 +0,1 @@

{"version":3,"file":"createTheme.cjs","sources":["../src/createTheme.js"],"sourcesContent":["import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\nconst makeCssVars = (theme = {}, prefix = '--') => {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n if (isObject(value)) {\n Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[`${prefix}-${key}`] = value;\n }\n return acc;\n }, {});\n};\n\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`. \n * For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":["isObject"],"mappings":"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"}
{"version":3,"file":"createTheme.cjs","sources":["../src/createTheme.js"],"sourcesContent":["import css from './css.js';\nimport StyleSheet from './StyleSheet.js';\nimport isObject from './utils/isObject.js';\n\n/**\n * Flattens a nested theme object into a map of CSS variable names to values.\n * Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).\n * @private\n * @param {Object} [theme={}] - Nested theme object.\n * @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.\n * @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.\n */\nconst makeCssVars = (theme = {}, prefix) => {\n function build(theme, nameAcc) {\n return Object.keys(theme).reduce((acc, key) => {\n const value = theme[key];\n const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;\n\n if (isObject(value)) {\n Object.assign(acc, build(value, name));\n } else if (typeof value !== 'undefined' && value !== null) {\n acc[name] = value;\n }\n\n return acc;\n }, {});\n }\n return build(theme);\n};\n\n/**\n * Returns keys that differ between two objects, with each side’s value.\n * @private\n * @param {Object} left - First object.\n * @param {Object} right - Second object.\n * @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.\n */\nconst getDiff = (left, right) => {\n return Object.keys(left).reduce((acc, key) => {\n if (left[key] !== right[key]) {\n acc.left[key] = left[key];\n acc.right[key] = right[key];\n }\n return acc;\n }, { left : {}, right : {} });\n};\n\n/**\n * The `createTheme` function generates a theme StyleSheet instance with CSS variables \n * based on the provided themes and options. It supports multiple color schemes, \n * including `light`, `dark`, `light dark`, and `normal`. \n * \n * The `themes` object defines the styles for these color schemes. Each key in the object \n * corresponds to a color scheme (`light`, `dark`, `normal`), and its value is an object \n * containing key-value pairs that will be converted into CSS variables. Nested keys are \n * concatenated with `-` to form the variable name. For example, `{ light : { colors : { primary : 'blue' } } }` \n * generates `--fun-colors-primary : blue`.\n * \n * @module\n * @function\n * @param {Object} themes - An object defining styles for color schemes (`light`, `dark`, `normal`). \n * Each key corresponds to a color scheme, and its value is an object of key-value pairs converted \n * to CSS variables. Nested keys are concatenated with `-` to form variable names.\n * \n * @param {Object} [options] - An optional object to customize the theme generation. It includes options \n * for selecting color schemes, customizing CSS variable prefixes, and controlling StyleSheet creation.\n * \n * @param {String} [options.colorScheme] - Specifies the color scheme(s) to use. Possible values are: \n * `light` (uses the `light` theme only), `dark` (uses the `dark` theme only), `light dark` (default, \n * supports both `light` and `dark` themes, adapting to system preferences; can override system \n * preference with `data-color-scheme` set to `light` or `dark`), and `normal` (uses the `normal` theme only).\n * \n * @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.\n * Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).\n * \n * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance. \n * By default, it uses the `css` function.\n * \n * @param {Object} [options.styleSheetOptions] - Options to pass when creating the StyleSheet instance. \n * Default is `system`.\n * \n * @returns {StyleSheet} The theme StyleSheet instance. Use `classes.root` to get the theme class name. \n * Apply this class to the element you want to theme. The CSS variables will be available for all \n * its descendants.\n * \n * @example\n * // Create a theme with light and dark color schemes and apply it to the entire page.\n * const theme = createTheme({\n * light : {\n * colorPrimary : 'black',\n * backgroundLevel1 : 'white'\n * },\n * dark : {\n * colorPrimary : 'white',\n * backgroundLevel1 : 'black'\n * }\n * });\n * \n * // Add the `root` class (the theme class) to the body element.\n * // This will apply the theme to the entire page.\n * document.body.classList.add(theme.classes.root);\n * \n * // Add some styles using the theme CSS variables.\n * const { classes } = css({\n * button : {\n * color : 'var(--fun-colorPrimary)', // Use the CSS variable generated from the theme.\n * backgroundColor : 'var(--fun-backgroundLevel1)'\n * }\n * });\n * \n * // Add the `button` class to a button component.\n * // The button will use the CSS variables defined in the theme for its styles.\n * // Once the theme is applied, the button will automatically update its styles.\n * // If the system color scheme changes (e.g., from light to dark), the button will \n * // dynamically update to reflect the new theme without requiring additional code.\n * const Button = ({ label }) => <button className={classes.button}>{label}</button>;\n */\nconst createTheme = (themes = {}, options = {}) => {\n const colorScheme = options.colorScheme || 'light dark';\n const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;\n\n let styles;\n\n if (colorScheme === 'light dark') {\n const cssVars = {\n light : makeCssVars(themes.light, prefix),\n dark : makeCssVars(themes.dark, prefix)\n };\n\n const diff = getDiff(cssVars.light, cssVars.dark);\n\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme : 'light' }, cssVars.light),\n ':where([data-color-scheme=\"dark\"] &)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n },\n '@media (prefers-color-scheme: dark)' : {\n ':where($root)' : Object.assign({ colorScheme : 'dark' }, diff.right),\n ':where([data-color-scheme=\"light\"] $root)' : Object.assign({ colorScheme : 'light' }, diff.left)\n }\n };\n } else {\n styles = {\n root : {\n ':where(&)' : Object.assign({ colorScheme }, makeCssVars(themes[colorScheme], prefix))\n }\n };\n }\n\n return (options.createStyleSheet || css)(styles, options.styleSheetOptions);\n};\n\nexport default createTheme;\n"],"names":["isObject"],"mappings":"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"}
{
"name": "cssfun",
"version": "0.0.13",
"version": "0.0.14",
"description": "Near-zero runtime CSS-in-JS library",

@@ -28,3 +28,3 @@ "type": "module",

"prepare": "npm run clean && npm run test && npm run build",
"clean": "rimraf lib dist es",
"clean": "node -e \"const fs=require('fs');['lib','dist','es'].forEach(d=>fs.rmSync(d,{recursive:true,force:true}))\"",
"test": "mocha --require jsdom-global/register --reporter nyan test/*.js",

@@ -59,14 +59,13 @@ "posttest": "npm run lint",

"@rollup/plugin-replace": "^6.0.3",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-terser": "^1.0.0",
"chai": "^6.0.1",
"eslint": "^9.34.0",
"glob": "^13.0.0",
"glob": "^13.0.6",
"globals": "^16.3.0",
"jsdoc-to-markdown": "^9.1.2",
"jsdom": "^26.1.0",
"jsdom": "^29.0.1",
"jsdom-global": "3.0.2",
"mocha": "^11.7.1",
"rimraf": "^6.0.1",
"rollup": "^4.48.1"
"mocha": "^11.7.5",
"rollup": "^4.60.1"
}
}
+75
-17
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/cssfun@v0.0.13/docs/logo-dark.svg">
<img alt="CSSFUN" src="https://cdn.jsdelivr.net/gh/8tentaculos/cssfun@v0.0.13/docs/logo.svg">
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/cssfun@v0.0.14/docs/logo-dark.svg">
<img alt="CSSFUN" src="https://cdn.jsdelivr.net/gh/8tentaculos/cssfun@v0.0.14/docs/logo.svg">
</picture>

@@ -14,6 +14,6 @@ </p>

[![npm version](https://img.shields.io/npm/v/cssfun.svg?style=flat-square)](https://www.npmjs.com/package/cssfun)
[![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/cssfun?style=flat-square)](https://unpkg.com/cssfun/dist/cssfun.min.js)
[![npm downloads](https://img.shields.io/npm/dm/cssfun.svg?style=flat-square)](https://www.npmjs.com/package/cssfun)
[![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/cssfun?style=flat-square)](https://www.jsdelivr.com/package/npm/cssfun)
[![npm version](https://img.shields.io/npm/v/cssfun.svg)](https://www.npmjs.com/package/cssfun)
[![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/cssfun)](https://unpkg.com/cssfun/dist/cssfun.min.js)
[![npm downloads](https://img.shields.io/npm/dm/cssfun.svg)](https://www.npmjs.com/package/cssfun)
[![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/cssfun)](https://www.jsdelivr.com/package/npm/cssfun)

@@ -91,14 +91,50 @@ ## Key Features

## Class Name Generation
When you call `css()`, **CSSFUN** automatically generates unique, scoped class names for each top-level selector in your styles object. These class names are created **at module initialization**, ensuring near-zero runtime overhead.
### How Classes Are Generated
1. **When**: Classes are generated immediately when `css()` is called, during the StyleSheet instance creation.
2. **Which selectors**: Only top-level selectors that match valid class name patterns (alphanumeric characters, no special characters) get generated classes.
3. **Format**: The format differs between development and production modes:
**Development Mode** (readable, for debugging):
```
{prefix}-{uid}-{className}
```
Example: `.fun-9qkk9s-button` (prefix `fun` + unique ID `9qkk9s` + original class name `button`)
**Production Mode** (optimized, smaller bundle):
```
{prefix[0]}-{uid}-{index}
```
Example: `.f-9qkk9s-1` (first letter of prefix `f` + unique ID `9qkk9s` + sequential index `1`)
4. **Access**: Generated class names are available via the `classes` object returned by `css()`:
```javascript
const { classes } = css({
button: { color: 'red' },
link: { color: 'blue' }
});
// classes.button → "fun-9qkk9s-button" (dev) or "f-9qkk9s-1" (prod)
// classes.link → "fun-9qkk9s-link" (dev) or "f-9qkk9s-2" (prod)
```
> **Note**: All examples in this documentation show class names in **development mode** for clarity.
> In **production**, class names are automatically optimized for smaller bundle size.
> You can customize class name generation via [`options.generateClassName`](/docs/api.md#new-stylesheetstyles-options) or by [extending the class](/docs/api.md#stylesheet__generateclassname).
## Renderers
Renderers are functions that transform style objects into CSS strings.
Renderers are functions that transform style objects into CSS strings. They are applied in sequence, with each renderer receiving the output of the previous one.
**CSSFUN** uses two built-in renderers by default:
1. **`parseStyles`**: Transforms the style object (expands nested selectors, replaces class references, converts camelCase to dashed-case, handles global styles)
2. **`renderStyles`**: Converts the processed object into a CSS string
The final renderer in the chain outputs the CSS string that gets injected into the DOM.
These are the built-in renderers transformations:
> **Note**: All examples below show class names generated in **development mode**.
> In **production**, class names are optimized for smaller bundle size:
> - **Development**: `.fun-9qkk9s-root { color: red; }` (full prefix + class name)
> - **Production**: `.f-9qkk9s-1{color:red;}` (first letter of prefix + index)
>
> Customize via [`options.generateClassName`](/docs/api.md#new-stylesheetstyles-options) or by [extending the class](/docs/api.md#stylesheet__generateclassname).
#### Camelized keys will be transformed to dashed keys

@@ -109,3 +145,5 @@

root : {
backgroundColor : 'black'
backgroundColor : 'black',
fontSize : '16px',
paddingTop : '10px'
}

@@ -121,2 +159,4 @@ }).toString();

background-color: black;
font-size: 16px;
padding-top: 10px;
}

@@ -311,4 +351,16 @@ </style>

When composed, the first renderer receives the styles object, and the final one outputs the
resulting CSS string.
resulting CSS string. The renderers are applied in sequence: each renderer receives the output
of the previous one.
**Example flow:**
```
Input styles object
[parseStyles] → Transforms object (expands nested, replaces references, converts camelCase)
[renderStyles] → Converts object to CSS string
Output CSS string
```
### Custom Renderers

@@ -322,4 +374,6 @@

By default, [`StyleSheet`](/docs/api.md#stylesheet) are rendered using the built-in renderers: `[this.renderStyles, this.parseStyles]`.
By default, [`StyleSheet`](/docs/api.md#stylesheet) instances are rendered using the built-in renderers: `[this.renderStyles, this.parseStyles]`.
**Note:** The order matters! Renderers are composed, so they execute in reverse order. With `[renderStyles, parseStyles]`, `parseStyles` executes first (transforms the object), then `renderStyles` (converts to CSS string).
## Themes

@@ -483,2 +537,6 @@

## Working with LLMs
For those working with LLMs, there is an [AI Agents reference guide](/docs/AGENTS.md) that provides API patterns, style syntax, theme management, and best practices, optimized for LLM context. You can share this guide with AI assistants to help them understand **CSSFUN**'s architecture and styling APIs.
## Examples

@@ -485,0 +543,0 @@

@@ -5,14 +5,35 @@ import css from './css.js';

const makeCssVars = (theme = {}, prefix = '--') => {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
if (isObject(value)) {
Object.assign(acc, makeCssVars(value, `${prefix}-${key}`));
} else if (typeof value !== 'undefined' && value !== null) {
acc[`${prefix}-${key}`] = value;
}
return acc;
}, {});
/**
* Flattens a nested theme object into a map of CSS variable names to values.
* Nested keys are joined with `-` (e.g. `{ colors: { primary: 'blue' } }` → `--prefix-colors-primary`).
* @private
* @param {Object} [theme={}] - Nested theme object.
* @param {string|null} [prefix] - Prefix for variable names (e.g. `fun` → `--fun-key`). Omit or pass `null`/`''` for no prefix.
* @returns {Object} Map of CSS variable names (e.g. `--fun-color`) to values.
*/
const makeCssVars = (theme = {}, prefix) => {
function build(theme, nameAcc) {
return Object.keys(theme).reduce((acc, key) => {
const value = theme[key];
const name = nameAcc ? `${nameAcc}-${key}` : prefix ? `--${prefix}-${key}` : `--${key}`;
if (isObject(value)) {
Object.assign(acc, build(value, name));
} else if (typeof value !== 'undefined' && value !== null) {
acc[name] = value;
}
return acc;
}, {});
}
return build(theme);
};
/**
* Returns keys that differ between two objects, with each side’s value.
* @private
* @param {Object} left - First object.
* @param {Object} right - Second object.
* @returns {{ left: Object, right: Object }} Objects containing only the differing keys and their values per side.
*/
const getDiff = (left, right) => {

@@ -53,4 +74,4 @@ return Object.keys(left).reduce((acc, key) => {

*
* @param {String} [options.cssVarsPrefix] - The prefix for the generated CSS variables. Default is `fun`.
* For example, a key `color` in the theme will generate a CSS variable like `--fun-color`.
* @param {String|null} [options.cssVarsPrefix] - Prefix for the generated CSS variables. Defaults to `StyleSheet.prefix`.
* Pass `null` or `''` to generate variables without a prefix (e.g. `--color` instead of `--fun-color`).
*

@@ -101,3 +122,3 @@ * @param {Function} [options.createStyleSheet] - A function used to create a new StyleSheet instance.

const colorScheme = options.colorScheme || 'light dark';
const prefix = `--${options.cssVarsPrefix || StyleSheet.prefix}`;
const prefix = 'cssVarsPrefix' in options ? options.cssVarsPrefix : StyleSheet.prefix;

@@ -104,0 +125,0 @@ let styles;

Sorry, the diff of this file is too big to display