utilikit-1.0.0/js/utilikit.helpers.js
js/utilikit.helpers.js
/**
* @file
* Utility helper functions for UtiliKit CSS processing and validation.
*
* This file provides essential utility functions used throughout the UtiliKit
* system for color parsing, transform handling, breakpoint validation, and
* error reporting. These helpers abstract common operations and provide
* consistent interfaces for complex parsing and validation tasks.
*
* Key Helper Categories:
* - Color Processing: Hex color parsing with alpha channel support
* - Responsive Utilities: Breakpoint validation and screen size checking
* - CSS Transform Management: Safe transform property manipulation
* - Value Conversion: Decimal notation and unit conversion utilities
* - Error Handling: Comprehensive validation error reporting system
*
* Integration Points:
* - Used by CSS generation engine for value parsing and validation
* - Integrates with logging system for consistent error reporting
* - Supports development mode with enhanced debugging capabilities
* - Provides cross-browser compatibility for CSS property handling
* - Enables consistent validation across all UtiliKit utility classes
*
* Design Principles:
* - Defensive programming with comprehensive input validation
* - Graceful error handling that doesn't break functionality
* - Performance optimization through efficient parsing algorithms
* - Development-friendly error messages with actionable feedback
* - Cross-browser compatibility for all supported operations
*/
(function(Drupal, once, drupalSettings) {
'use strict';
// Ensure UtiliKit namespace exists for helper functions
Drupal.utilikit = Drupal.utilikit || {};
/**
* Parses hex color strings with optional alpha channel into valid CSS colors.
*
* This function handles both 3-digit and 6-digit hex color formats with
* optional alpha transparency values. It supports UtiliKit's custom syntax
* for specifying alpha values as percentages (0-100) appended with a dash.
* The function automatically converts between hex and rgba formats based
* on whether alpha transparency is specified.
*
* Supported Formats:
* - 6-digit hex: "ff0000" -> "#ff0000"
* - 6-digit hex with alpha: "ff0000-50" -> "rgba(255, 0, 0, 0.5)"
* - 3-digit hex: "f00" -> "#f00" (expanded to #ff0000)
* - 3-digit hex with alpha: "f00-25" -> "rgba(255, 0, 0, 0.25)"
*
* @param {string} suffix
* The color value suffix from a utility class, containing the hex color
* and optional alpha value. Examples: "ff0000", "ff0000-50", "f00-25"
*
* @returns {string|null}
* Returns a valid CSS color string ("#hexvalue" or "rgba(r, g, b, a)")
* or null if the input format is invalid or cannot be parsed.
*
* @example
* // Solid red color (6-digit hex)
* parseColorWithAlpha('ff0000')
* // Returns: "#ff0000"
*
* @example
* // Red with 50% transparency
* parseColorWithAlpha('ff0000-50')
* // Returns: "rgba(255, 0, 0, 0.5)"
*
* @example
* // Short hex format with transparency
* parseColorWithAlpha('f00-25')
* // Returns: "rgba(255, 0, 0, 0.25)"
*
* @example
* // Invalid format returns null
* parseColorWithAlpha('invalid')
* // Returns: null
*/
Drupal.utilikit.parseColorWithAlpha = function(suffix) {
let match;
// Match 6-digit hex color with optional alpha percentage (0-100)
if ((match = suffix.match(/^([0-9a-fA-F]{6})(?:-(\d{1,3}))?$/))) {
const hex = match[1];
const alpha = match[2] !== undefined ? Math.min(parseInt(match[2], 10), 100) / 100 : 1;
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return alpha < 1 ? `rgba(${r}, ${g}, ${b}, ${alpha})` : `#${hex}`;
}
// Match 3-digit hex color with optional alpha percentage (0-100)
if ((match = suffix.match(/^([0-9a-fA-F]{3})(?:-(\d{1,3}))?$/))) {
// Expand 3-digit hex to 6-digit by doubling each character
const hex = match[1].split('').map(ch => ch + ch).join('');
const alpha = match[2] !== undefined ? Math.min(parseInt(match[2], 10), 100) / 100 : 1;
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return alpha < 1 ? `rgba(${r}, ${g}, ${b}, ${alpha})` : `#${hex}`;
}
return null; // Invalid format
};
/**
* Checks if a responsive breakpoint applies to the current viewport width.
*
* This function implements mobile-first breakpoint logic by checking if
* the current viewport width meets or exceeds the minimum width threshold
* for the specified breakpoint. It provides the foundation for responsive
* utility class application and ensures consistent behavior across the
* UtiliKit system.
*
* The function uses window.innerWidth for accurate viewport detection
* and integrates with UtiliKit's breakpoint configuration system for
* consistent behavior with CSS media queries.
*
* @param {string} bp
* The breakpoint identifier to check. Must be one of the configured
* breakpoint names: 'sm', 'md', 'lg', 'xl', 'xxl'.
*
* @returns {boolean}
* TRUE if the current viewport width is greater than or equal to
* the breakpoint's minimum width threshold, FALSE otherwise.
*
* @example
* // Check if medium breakpoint applies (viewport >= 768px)
* if (Drupal.utilikit.breakpointApplies('md')) {
* // Apply medium-screen specific logic
* }
*
* @example
* // Conditional processing based on breakpoint
* const isLargeScreen = Drupal.utilikit.breakpointApplies('lg');
* const columnCount = isLargeScreen ? 4 : 2;
*
* @example
* // Validate breakpoint before processing utility class
* if (responsivePrefix && !Drupal.utilikit.breakpointApplies(responsivePrefix)) {
* return; // Skip processing for inapplicable breakpoint
* }
*/
Drupal.utilikit.breakpointApplies = function(bp) {
const minWidth = Drupal.utilikit.breakpoints[bp];
return typeof minWidth === 'number' && window.innerWidth >= minWidth;
};
/**
* Converts UtiliKit's decimal notation using 'd' to standard CSS decimal format.
*
* UtiliKit uses 'd' as a decimal separator in utility class names to avoid
* conflicts with CSS class naming conventions that don't support dots.
* This function converts the custom notation back to standard decimal
* format for CSS value generation.
*
* The conversion is essential for numeric values in utility classes
* such as fractional units (0.5fr becomes 0d5fr in class names) and
* decimal measurements that need standard CSS syntax.
*
* @param {string} value
* A value string that may contain 'd' characters as decimal separators.
* Examples: "0d5", "1d25", "2d75fr"
*
* @returns {string}
* The same value with all 'd' characters replaced by '.' for standard
* CSS decimal notation. Examples: "0.5", "1.25", "2.75fr"
*
* @example
* // Convert fractional unit notation
* convertDecimalNotation('0d5fr')
* // Returns: "0.5fr"
*
* @example
* // Convert decimal measurement
* convertDecimalNotation('1d25rem')
* // Returns: "1.25rem"
*
* @example
* // Handle multiple decimal places
* convertDecimalNotation('2d75')
* // Returns: "2.75"
*
* @example
* // No change needed for values without 'd'
* convertDecimalNotation('100px')
* // Returns: "100px"
*/
Drupal.utilikit.convertDecimalNotation = function(value) {
return value.replace(/d/g, '.');
};
/**
* Safely applies CSS transform functions without overwriting existing transforms.
*
* This function manages CSS transform properties by preserving existing
* transform functions while updating or adding specific transform types.
* It prevents conflicts between multiple transform utilities applied to
* the same element by maintaining a composite transform value.
*
* The function parses existing transform values, removes any transforms
* of the same type being applied, and appends the new transform while
* preserving all other transform functions. This ensures predictable
* behavior when multiple transform utilities are combined.
*
* @param {HTMLElement} el
* The DOM element to apply the transform to. Must be a valid HTMLElement
* with access to the style property for CSS manipulation.
* @param {string} type
* The type of transform to apply. Supported values: 'rotate', 'scale'.
* Additional transform types can be added by extending the function logic.
* @param {number} value
* The numeric value for the transform. For 'rotate', this represents
* degrees of rotation. For 'scale', this represents a percentage where
* 100 equals normal size (1.0 scale factor).
*
* @example
* // Apply 45-degree rotation to an element
* const element = document.querySelector('.my-element');
* Drupal.utilikit.parseTransform(element, 'rotate', 45);
* // Result: element.style.transform includes "rotate(45deg)"
*
* @example
* // Scale element to 150% while preserving existing rotation
* Drupal.utilikit.parseTransform(element, 'scale', 150);
* // Result: element.style.transform includes both transforms
*
* @example
* // Update existing transform of same type
* Drupal.utilikit.parseTransform(element, 'rotate', 90);
* // Result: Previous rotation is replaced, scale is preserved
*/
Drupal.utilikit.parseTransform = function(el, type, value) {
let transform = el.style.transform || '';
// Remove any existing transform of the same type to prevent duplicates
const regex = new RegExp(`${type}\\([^)]*\\)`, 'g');
transform = transform.replace(regex, '').trim();
// Append the new transform function based on type
if (type === 'rotate') {
transform += ` rotate(${value}deg)`;
}
if (type === 'scale') {
// Convert percentage to decimal scale factor (100% = 1.0)
transform += ` scale(${value / 100})`;
}
// Apply the composite transform value, removing extra whitespace
el.style.transform = transform.trim();
};
/**
* Logs validation errors with comprehensive context and optional UI feedback.
*
* This function provides centralized error reporting for utility class
* validation failures, with support for both console logging and optional
* user interface notifications in development mode. It ensures consistent
* error messaging across the UtiliKit system and provides actionable
* feedback for developers debugging utility class issues.
*
* The function respects development mode configuration and can display
* errors both in the browser console and as Drupal messages when
* appropriate settings are enabled. This dual approach supports different
* development workflows and debugging preferences.
*
* @param {string} message
* The primary error description explaining what validation failed.
* Should be clear and actionable for developers. Examples: "Invalid unit",
* "Unknown color format", "Value out of range".
* @param {string} suffix
* The specific invalid value that caused the validation failure.
* This provides context about what the developer attempted to use.
* @param {Object} rule
* The UtiliKit rule definition object containing metadata about the
* utility class being processed, including the CSS property name.
* @param {string} className
* The complete utility class name that triggered the validation error.
* Provides full context for debugging and error identification.
*
* @example
* // Log invalid unit error
* Drupal.utilikit.logInvalid(
* 'Invalid unit',
* 'x100',
* { css: 'padding' },
* 'uk-pd--x100'
* );
*
* @example
* // Log color format error
* Drupal.utilikit.logInvalid(
* 'Invalid color format',
* 'notacolor',
* { css: 'background-color' },
* 'uk-bg--notacolor'
* );
*
* @example
* // Log range validation error
* Drupal.utilikit.logInvalid(
* 'Value out of range (0-100)',
* '150',
* { css: 'opacity' },
* 'uk-op--150'
* );
*/
Drupal.utilikit.logInvalid = function(message, suffix, rule, className) {
const errorMsg = `UtiliKit: ${message} "${suffix}" for "${rule.css}" in class "${className}".`;
const settings = drupalSettings.utilikit || {};
const isDevMode = !!settings.devMode;
const showPageErrors = !!settings.showPageErrors;
// Only process errors in development mode for security and performance
if (isDevMode) {
// Console logging with UtiliKit's logging system integration
if (typeof Drupal.utilikit.utilikitLog === 'function') {
Drupal.utilikit.utilikitLog(errorMsg, null, 'warn');
} else {
// Fallback to direct console warning if logging system unavailable
console.warn(errorMsg);
}
// Optional UI notifications for immediate visual feedback
if (showPageErrors && typeof Drupal.Message === 'function') {
const messages = new Drupal.Message();
messages.add(errorMsg, {
type: 'warning'
});
}
}
};
})(Drupal, once, drupalSettings);
/**
* Integration Notes for UtiliKit Helper Functions:
*
* Color Processing Integration:
* - parseColorWithAlpha integrates with CSS property generation for color utilities
* - Supports both solid colors and transparency for modern design requirements
* - Handles browser compatibility for rgba() vs hex color formats
* - Validates color input to prevent invalid CSS generation
* - Provides consistent color handling across all UtiliKit color utilities
*
* Responsive System Integration:
* - breakpointApplies provides foundation for responsive utility class logic
* - Integrates with UtiliKit's breakpoint configuration and detection system
* - Ensures consistent mobile-first behavior across all responsive utilities
* - Supports dynamic breakpoint checking during resize events
* - Enables performance optimization by skipping inapplicable breakpoints
*
* CSS Transform Management:
* - parseTransform enables safe composition of multiple transform utilities
* - Prevents conflicts between different transform types on same element
* - Maintains existing transforms while updating specific transform functions
* - Supports extensible transform types for future utility class additions
* - Provides consistent transform syntax generation for cross-browser compatibility
*
* Value Conversion and Validation:
* - convertDecimalNotation enables CSS-compliant decimal values from class names
* - Supports fractional units and precise numeric values in utility classes
* - Maintains readability in class names while generating valid CSS
* - Provides foundation for complex numeric utility class patterns
* - Enables consistent value parsing across all numeric utility types
*
* Error Handling and Development Support:
* - logInvalid provides comprehensive error context for debugging utility classes
* - Integrates with UtiliKit's logging system for consistent error reporting
* - Supports both console and UI-based error notifications for different workflows
* - Respects development mode configuration for security in production
* - Provides actionable error messages for rapid debugging and resolution
*
* Performance and Efficiency Considerations:
* - Helper functions are optimized for frequent usage during CSS generation
* - Input validation prevents expensive operations on invalid data
* - Efficient regular expressions and string operations for parsing
* - Minimal DOM manipulation and memory allocation in processing loops
* - Graceful degradation when optional dependencies are unavailable
*
* Browser Compatibility and Standards:
* - Cross-browser viewport detection using standard window.innerWidth
* - Standards-compliant CSS value generation for all supported properties
* - Graceful handling of browser-specific transform syntax requirements
* - Compatible color format generation supporting legacy and modern browsers
* - Robust parsing algorithms that handle edge cases and invalid input
*
* Development Workflow Integration:
* - Helper functions support real-time validation during development
* - Error reporting integrates with browser developer tools for debugging
* - Comprehensive logging supports troubleshooting complex utility combinations
* - Development mode features enhance productivity without affecting production
* - Consistent error messaging helps developers quickly identify and resolve issues
*/
