/** * Styled Components for Fluent Grow * Provides a styled-components-like API */ import { css as cssTemplate } from '../utils/css-template'; /** * Enhanced CSS function that can work as both template literal and element styler */ export function css(elementOrTemplate: HTMLElement | TemplateStringsArray, ...values: any[]): any { // If first argument is HTMLElement, return FluentCSS instance if (elementOrTemplate instanceof HTMLElement) { // Dynamic import to avoid circular dependencies import('../css-complete').then(({ FluentCSS }) => { return new FluentCSS(elementOrTemplate); }); } // If first argument is TemplateStringsArray, use template literal function if (Array.isArray(elementOrTemplate) && 'raw' in elementOrTemplate) { return cssTemplate(elementOrTemplate as TemplateStringsArray, ...values); } // If string selector, find element and return FluentCSS if (typeof elementOrTemplate === 'string') { const element = document.querySelector(elementOrTemplate); if (!element) throw new Error(`Element not found: ${elementOrTemplate}`); // Dynamic import to avoid circular dependencies import('../css-complete').then(({ FluentCSS }) => { return new FluentCSS(element as HTMLElement); }); } throw new Error('Invalid arguments for css function'); } /** * Styled component factory */ export function styled(tag: string) { return function(strings: TemplateStringsArray, ...values: any[]) { const className = cssTemplate(strings, ...values); return function StyledComponent(props: any = {}) { const { children, className: additionalClass, ...otherProps } = props; // Create element const element = document.createElement(tag); // Apply className element.className = additionalClass ? `${className} ${additionalClass}` : className; // Apply other props as attributes Object.entries(otherProps).forEach(([key, value]) => { if (key.startsWith('on') && typeof value === 'function') { // Event listeners const eventName = key.slice(2).toLowerCase(); element.addEventListener(eventName, value as EventListener); } else if (key === 'style' && typeof value === 'object') { // Style object Object.assign(element.style, value); } else { // Regular attributes element.setAttribute(key, String(value)); } }); // Add children if (children) { if (typeof children === 'string') { element.textContent = children; } else if (children instanceof HTMLElement) { element.appendChild(children); } else if (Array.isArray(children)) { children.forEach(child => { if (typeof child === 'string') { element.appendChild(document.createTextNode(child)); } else if (child instanceof HTMLElement) { element.appendChild(child); } }); } } return element; }; }; } // Pre-defined styled elements export const StyledDiv = styled('div'); export const StyledSpan = styled('span'); export const StyledButton = styled('button'); export const StyledInput = styled('input'); export const StyledSection = styled('section'); export const StyledArticle = styled('article'); export const StyledHeader = styled('header'); export const StyledFooter = styled('footer'); export const StyledNav = styled('nav'); export const StyledMain = styled('main'); export const StyledAside = styled('aside'); /** * Theme provider for styled components */ export class ThemeProvider { private static theme: Record = {}; static setTheme(theme: Record): void { ThemeProvider.theme = { ...ThemeProvider.theme, ...theme }; } static getTheme(): Record { return ThemeProvider.theme; } static useTheme(): Record { return ThemeProvider.theme; } } /** * CSS variables helper */ export function cssVar(name: string, fallback?: string): string { return fallback ? `var(--${name}, ${fallback})` : `var(--${name})`; } /** * Responsive breakpoints helper */ export const breakpoints = { mobile: '(max-width: 767px)', tablet: '(min-width: 768px) and (max-width: 1023px)', desktop: '(min-width: 1024px)', large: '(min-width: 1440px)', }; /** * Media query helper */ export function mediaQuery(breakpoint: keyof typeof breakpoints | string): string { const query = breakpoints[breakpoint as keyof typeof breakpoints] || breakpoint; return `@media ${query}`; } /** * Container query helper */ export function containerQuery(condition: string): string { return `@container ${condition}`; }