UNPKG

jacaranda

Version:

A lightweight styling library for React Native

235 lines (233 loc) 9.52 kB
/** * ISC License * Copyright 2025 Javier Diaz Chamorro * * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby * granted, provided that the above copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE * OR PERFORMANCE OF THIS SOFTWARE. */ // Example of usage: // const buttonStyles = style({ // base: { // display: 'flex', // }, // variants: { // visual: { // solid: { backgroundColor: '#FC8181', color: 'white' }, // outline: { borderWidth: 1, borderColor: '#FC8181' }, // }, // size: { // sm: { padding: 4, fontSize: 12 }, // lg: { padding: 8, fontSize: 24 }, // }, // }, // // Optional: Add compound variants for specific combinations // compoundVariants: [ // { // variants: { visual: 'solid', size: ['lg'] }, // style: { fontWeight: 'bold' }, // }, // ], // defaultVariants: { // visual: 'solid', // size: 'sm', // } // }); // Example of using a styled component with a custom prop // const button = styled(Button)<{ otherProp: string }>((props) => { // position: props.otherProp ? 'absolute' : 'relative'; // }); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "defineTokens", { enumerable: true, get: function() { return defineTokens; } }); const _react = /*#__PURE__*/ _interop_require_default(require("react")); const _reactnative = require("react-native"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Creates a function that generates styles based on variants */ function styles(config) { return (props)=>{ // We'll build up styles in the correct hierarchy: base → variants → compound variants // Base styles (lowest priority) let stylesObj = { ...config.base || {} }; // Merge default variants with provided props const mergedProps = { ...config.defaultVariants || {}, ...props }; // Apply variant styles (overrides base styles) for (const [propName, value] of Object.entries(mergedProps)){ const variantGroup = config.variants[propName]; if (variantGroup) { // Handle boolean variants if (typeof value === "boolean") { const booleanValue = value ? "true" : "false"; if (variantGroup[booleanValue]) { stylesObj = { ...stylesObj, ...variantGroup[booleanValue] }; } } else { var _config_defaultVariants; // Handle string/enum variants const variantValue = value || ((_config_defaultVariants = config.defaultVariants) === null || _config_defaultVariants === void 0 ? void 0 : _config_defaultVariants[propName]); if (variantValue && variantGroup[variantValue]) { stylesObj = { ...stylesObj, ...variantGroup[variantValue] }; } } } } // Apply compound variants (highest priority before inline styles) if (config.compoundVariants) { for (const compound of config.compoundVariants){ if (Object.entries(compound.variants).every((param)=>{ let [propName, value] = param; // Handle boolean values in compound variants if (typeof value === "boolean") { return mergedProps[propName] === value; } // Handle array of values if (Array.isArray(value)) { return value.includes(mergedProps[propName]); } // Handle single value (string/enum) return mergedProps[propName] === value; })) { stylesObj = { ...stylesObj, ...compound.style }; } } } // Create a StyleSheet for better performance return _reactnative.StyleSheet.create({ style: stylesObj }).style; }; } // Helper to resolve token references in style objects function resolveTokens(style, tokens) { return Object.entries(style).reduce((acc, param)=>{ let [key, value] = param; if (typeof value !== "string" || !value.startsWith("$")) { acc[key] = value; return acc; } const tokenPath = value.slice(1).split("."); const [category, token] = tokenPath; const tokenCategory = tokens[category]; const tokenValue = tokenCategory === null || tokenCategory === void 0 ? void 0 : tokenCategory[token]; if (tokenValue !== undefined) { acc[key] = tokenValue; } return acc; }, {}); } function defineTokens(tokenConfig) { // Create the tokens object const tokens = Object.entries(tokenConfig).reduce((acc, param)=>{ let [category, values] = param; return { ...acc, [category]: values }; }, {}); // Create a wrapped styles function that resolves token references const sva = (config)=>{ var _config_compoundVariants; // Resolve tokens in base styles const resolvedBase = config.base ? resolveTokens(config.base, tokens) : config.base; // Resolve tokens in variants const resolvedVariants = config.variants ? Object.entries(config.variants).reduce((acc, param)=>{ let [key, variantGroup] = param; const resolvedGroup = Object.entries(variantGroup).reduce((groupAcc, param)=>{ let [variantKey, variantStyles] = param; return { ...groupAcc, [variantKey]: resolveTokens(variantStyles, tokens) }; }, {}); return { ...acc, [key]: resolvedGroup }; }, {}) : {}; // Resolve tokens in compound variants const resolvedCompoundVariants = (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.map((compound)=>({ ...compound, style: resolveTokens(compound.style, tokens) })); // Return the styles function with resolved tokens return styles({ ...config, base: resolvedBase, variants: resolvedVariants, compoundVariants: resolvedCompoundVariants }); }; /** * Styled function for creating styled components with token-aware styles */ const styled = (Component)=>{ return (styleObject)=>{ // Create and return a new component that applies the resolved styles const StyledComponent = (props)=>{ const { children, style: propStyle, ...rest } = props; // If styleObject is a function, call it with props to get the style object const styleToResolve = typeof styleObject === "function" ? styleObject(props) : styleObject; // Resolve tokens in the style object const resolvedStyle = resolveTokens(styleToResolve, tokens); // Create StyleSheet for the resolved style const styles = _reactnative.StyleSheet.create({ style: resolvedStyle }); // Styles hierarchy: base styles → variants → compound variants → inline styles // Inline styles (propStyle) must have highest priority, so they come last in the array const mergedStyle = propStyle ? [ styles.style, ...Array.isArray(propStyle) ? propStyle : [ propStyle ] ] : styles.style; // We need to cast here to handle the component props correctly const componentProps = { ...rest, style: mergedStyle }; // Use createElement instead of JSX to avoid syntax issues return _react.default.createElement(Component, componentProps, children); }; // Set display name for better debugging const componentName = Component.displayName || Component.name || "Component"; StyledComponent.displayName = `Styled(${componentName})`; return StyledComponent; }; }; return { sva, tokens, styled }; } //# sourceMappingURL=index.js.map