UNPKG

goobs-frontend

Version:

A comprehensive React-based libary for building modern web applications

551 lines (530 loc) 15.8 kB
// -------------------------------------------------------------------------- // CHIP THEME SYSTEM // -------------------------------------------------------------------------- import React from 'react' import { TRANSITIONS, SHADOWS } from './shared' export interface ChipTheme { container: { background: string border: string borderRadius: string boxShadow: string backdropFilter: string fontFamily: string fontSize: string fontWeight: string | number color: string textShadow?: string padding: string height: string backgroundImage?: string } containerHover: { transform: string boxShadow: string backgroundColor: string borderColor?: string color: string backgroundImage?: string } containerDisabled: { opacity: number backgroundColor: string color: string borderColor?: string textShadow?: string } closeButton: { marginLeft: string marginRight: string padding: string borderRadius: string border: string background: string color: string transition: string } closeButtonHover: { backgroundColor: string color: string transform: string boxShadow?: string } closeButtonDisabled: { color: string cursor: string } glyph: { position: string fontSize: string color: string transition: string pointerEvents: string zIndex: number } glyphLeft: { left: string top: string transform: string } glyphRight: { right: string top: string transform: string } glyphVisible: { opacity: number } shimmer: { position: string top: string left: string width: string height: string background: string animation: string } transition: string } export interface ChipStyles { // Theme selection theme?: 'light' | 'dark' | 'sacred' // Visual options outline?: boolean // Container styling backgroundColor?: string borderColor?: string borderRadius?: string borderWidth?: string boxShadow?: string backdropFilter?: string backgroundImage?: string fontFamily?: string fontSize?: string fontWeight?: string | number color?: string textShadow?: string padding?: string height?: string // Hover states hoverBackgroundColor?: string hoverBorderColor?: string hoverBoxShadow?: string hoverTransform?: string hoverColor?: string hoverBackgroundImage?: string // Disabled states disabledOpacity?: number disabledBackgroundColor?: string disabledColor?: string disabledBorderColor?: string disabledTextShadow?: string // Transitions transitionDuration?: string transitionEasing?: string // States disabled?: boolean // Dimensions width?: string maxWidth?: string minWidth?: string maxHeight?: string // Text wrapping whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line' wordBreak?: 'normal' | 'break-all' | 'keep-all' | 'break-word' wordWrap?: 'normal' | 'break-word' } export const chipThemes: Record<'light' | 'dark' | 'sacred', ChipTheme> = { light: { container: { background: 'rgba(59, 130, 246, 0.1)', border: '1px solid rgba(59, 130, 246, 0.2)', borderRadius: '16px', boxShadow: SHADOWS.light.small, backdropFilter: 'blur(4px)', fontFamily: 'Inter, system-ui, sans-serif', fontSize: '14px', fontWeight: '500', color: 'rgb(59, 130, 246)', padding: '4px 12px', height: 'auto', }, containerHover: { transform: 'translateY(-1px)', boxShadow: '0 4px 12px rgba(59, 130, 246, 0.2)', backgroundColor: 'rgba(59, 130, 246, 0.15)', borderColor: 'rgba(59, 130, 246, 0.3)', color: 'rgb(59, 130, 246)', }, containerDisabled: { opacity: 0.6, backgroundColor: 'rgba(156, 163, 175, 0.1)', color: 'rgb(156, 163, 175)', borderColor: 'rgba(156, 163, 175, 0.2)', }, closeButton: { marginLeft: '6px', marginRight: '-4px', padding: '2px', borderRadius: '50%', border: 'none', background: 'transparent', color: 'rgba(59, 130, 246, 0.7)', transition: TRANSITIONS.fast, }, closeButtonHover: { backgroundColor: 'rgba(59, 130, 246, 0.1)', color: 'rgb(59, 130, 246)', transform: 'scale(1.1)', }, closeButtonDisabled: { color: 'rgba(156, 163, 175, 0.5)', cursor: 'not-allowed', }, glyph: { position: 'absolute', fontSize: '10px', color: 'rgba(59, 130, 246, 0.2)', transition: TRANSITIONS.medium, pointerEvents: 'none', zIndex: 0, }, glyphLeft: { left: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphRight: { right: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphVisible: { opacity: 0.4, }, shimmer: { position: 'absolute', top: '0', left: '-100%', width: '100%', height: '100%', background: 'linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.2), transparent)', animation: 'sacredShimmer 3s ease-in-out infinite', }, transition: TRANSITIONS.medium, }, dark: { container: { background: 'rgba(59, 130, 246, 0.15)', border: '1px solid rgba(59, 130, 246, 0.3)', borderRadius: '16px', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.3)', backdropFilter: 'blur(4px)', fontFamily: 'Inter, system-ui, sans-serif', fontSize: '14px', fontWeight: '500', color: 'rgb(96, 165, 250)', padding: '4px 12px', height: 'auto', }, containerHover: { transform: 'translateY(-1px)', boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)', backgroundColor: 'rgba(59, 130, 246, 0.2)', borderColor: 'rgba(59, 130, 246, 0.4)', color: 'rgb(147, 197, 253)', }, containerDisabled: { opacity: 0.6, backgroundColor: 'rgba(75, 85, 99, 0.1)', color: 'rgb(75, 85, 99)', borderColor: 'rgba(75, 85, 99, 0.2)', }, closeButton: { marginLeft: '6px', marginRight: '-4px', padding: '2px', borderRadius: '50%', border: 'none', background: 'transparent', color: 'rgba(96, 165, 250, 0.7)', transition: TRANSITIONS.fast, }, closeButtonHover: { backgroundColor: 'rgba(96, 165, 250, 0.1)', color: 'rgb(147, 197, 253)', transform: 'scale(1.1)', }, closeButtonDisabled: { color: 'rgba(75, 85, 99, 0.5)', cursor: 'not-allowed', }, glyph: { position: 'absolute', fontSize: '10px', color: 'rgba(96, 165, 250, 0.2)', transition: TRANSITIONS.medium, pointerEvents: 'none', zIndex: 0, }, glyphLeft: { left: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphRight: { right: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphVisible: { opacity: 0.4, }, shimmer: { position: 'absolute', top: '0', left: '-100%', width: '100%', height: '100%', background: 'linear-gradient(90deg, transparent, rgba(96, 165, 250, 0.2), transparent)', animation: 'sacredShimmer 3s ease-in-out infinite', }, transition: TRANSITIONS.medium, }, sacred: { container: { background: 'rgba(10, 10, 10, 0.9)', border: '1px solid rgba(255, 215, 0, 0.3)', borderRadius: '20px', boxShadow: SHADOWS.sacred.small, backdropFilter: 'blur(8px)', fontFamily: 'Cinzel, serif', fontSize: '14px', fontWeight: '500', color: '#FFD700', padding: '0 16px', height: '32px', backgroundImage: 'radial-gradient(circle at center, rgba(255, 215, 0, 0.05) 0%, transparent 50%)', }, containerHover: { transform: 'translateY(-2px) scale(1.02)', boxShadow: SHADOWS.sacred.medium, backgroundColor: 'rgba(10, 10, 10, 0.95)', borderColor: 'rgba(255, 215, 0, 0.6)', color: '#FFD700', backgroundImage: 'radial-gradient(circle at center, rgba(255, 215, 0, 0.1) 0%, transparent 50%)', }, containerDisabled: { opacity: 0.4, backgroundColor: 'rgba(10, 10, 10, 0.6)', color: 'rgba(255, 215, 0, 0.3)', borderColor: 'rgba(255, 215, 0, 0.1)', }, closeButton: { marginLeft: '8px', marginRight: '-4px', padding: '3px', borderRadius: '50%', border: 'none', background: 'transparent', color: 'rgba(255, 215, 0, 0.7)', transition: TRANSITIONS.premium, }, closeButtonHover: { backgroundColor: 'rgba(255, 215, 0, 0.1)', color: '#FFD700', transform: 'scale(1.15) rotate(90deg)', boxShadow: '0 0 12px rgba(255, 215, 0, 0.3)', }, closeButtonDisabled: { color: 'rgba(255, 215, 0, 0.2)', cursor: 'not-allowed', }, glyph: { position: 'absolute', fontSize: '10px', color: 'rgba(255, 215, 0, 0.2)', transition: TRANSITIONS.premium, pointerEvents: 'none', zIndex: 0, }, glyphLeft: { left: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphRight: { right: '2px', top: '50%', transform: 'translateY(-50%)', }, glyphVisible: { opacity: 0.4, }, shimmer: { position: 'absolute', top: '0', left: '-100%', width: '100%', height: '100%', background: 'linear-gradient(90deg, transparent, rgba(255, 215, 0, 0.2), transparent)', animation: 'sacredShimmer 3s ease-in-out infinite', }, transition: TRANSITIONS.premium, }, } // Helper function to get computed theme with custom style overrides export const getChipTheme = (styles?: ChipStyles): ChipTheme => { const theme = styles?.theme || 'light' const baseTheme = chipThemes[theme] if (!styles) { return baseTheme } return { container: { background: styles.backgroundColor || baseTheme.container.background, border: styles.borderColor ? `${styles.borderWidth || '1px'} solid ${styles.borderColor}` : baseTheme.container.border, borderRadius: styles.borderRadius || baseTheme.container.borderRadius, boxShadow: styles.boxShadow || baseTheme.container.boxShadow, backdropFilter: styles.backdropFilter || baseTheme.container.backdropFilter, fontFamily: styles.fontFamily || baseTheme.container.fontFamily, fontSize: styles.fontSize || baseTheme.container.fontSize, fontWeight: styles.fontWeight || baseTheme.container.fontWeight, color: styles.color || baseTheme.container.color, textShadow: styles.textShadow || baseTheme.container.textShadow, padding: styles.padding || baseTheme.container.padding, height: styles.height || baseTheme.container.height, backgroundImage: styles.backgroundImage || baseTheme.container.backgroundImage, }, containerHover: { transform: styles.hoverTransform || baseTheme.containerHover.transform, boxShadow: styles.hoverBoxShadow || baseTheme.containerHover.boxShadow, backgroundColor: styles.hoverBackgroundColor || baseTheme.containerHover.backgroundColor, borderColor: styles.hoverBorderColor || baseTheme.containerHover.borderColor, color: styles.hoverColor || baseTheme.containerHover.color, backgroundImage: styles.hoverBackgroundImage || baseTheme.containerHover.backgroundImage, }, containerDisabled: { opacity: styles.disabledOpacity ?? baseTheme.containerDisabled.opacity, backgroundColor: styles.disabledBackgroundColor || baseTheme.containerDisabled.backgroundColor, color: styles.disabledColor || baseTheme.containerDisabled.color, borderColor: styles.disabledBorderColor || baseTheme.containerDisabled.borderColor, textShadow: styles.disabledTextShadow || baseTheme.containerDisabled.textShadow, }, closeButton: baseTheme.closeButton, closeButtonHover: baseTheme.closeButtonHover, closeButtonDisabled: baseTheme.closeButtonDisabled, glyph: baseTheme.glyph, glyphLeft: baseTheme.glyphLeft, glyphRight: baseTheme.glyphRight, glyphVisible: baseTheme.glyphVisible, shimmer: baseTheme.shimmer, transition: styles.transitionDuration ? `all ${styles.transitionDuration} ${styles.transitionEasing || 'cubic-bezier(0.4, 0, 0.2, 1)'}` : baseTheme.transition, } } // Main style generator function export const getChipStyles = ( styles?: ChipStyles, isHovered?: boolean, isDisabled?: boolean ) => { const themeConfig = getChipTheme(styles) const containerStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', position: 'relative', overflow: styles?.whiteSpace === 'normal' ? 'visible' : 'hidden', transition: themeConfig.transition, borderRadius: themeConfig.container.borderRadius, border: themeConfig.container.border, backgroundColor: themeConfig.container.background, backdropFilter: themeConfig.container.backdropFilter, boxShadow: themeConfig.container.boxShadow, cursor: 'default', fontFamily: themeConfig.container.fontFamily, fontSize: themeConfig.container.fontSize, fontWeight: themeConfig.container.fontWeight, color: themeConfig.container.color, textShadow: themeConfig.container.textShadow, padding: themeConfig.container.padding, height: themeConfig.container.height, backgroundImage: themeConfig.container.backgroundImage, // Layout styling width: styles?.width, maxWidth: styles?.maxWidth, minWidth: styles?.minWidth, maxHeight: styles?.maxHeight, // Text wrapping styling whiteSpace: styles?.whiteSpace, wordBreak: styles?.wordBreak, wordWrap: styles?.wordWrap, // State-based styling ...(isDisabled && { opacity: themeConfig.containerDisabled.opacity, backgroundColor: themeConfig.containerDisabled.backgroundColor, color: themeConfig.containerDisabled.color, borderColor: themeConfig.containerDisabled.borderColor, textShadow: themeConfig.containerDisabled.textShadow, transform: 'none', boxShadow: 'none', }), ...(isHovered && !isDisabled && { transform: themeConfig.containerHover.transform, boxShadow: themeConfig.containerHover.boxShadow, backgroundColor: themeConfig.containerHover.backgroundColor, borderColor: themeConfig.containerHover.borderColor, color: themeConfig.containerHover.color, backgroundImage: themeConfig.containerHover.backgroundImage, }), // Apply outline override ...(styles?.outline === false && { border: 'none', boxShadow: 'none', }), } const closeButtonStyle: React.CSSProperties = { ...themeConfig.closeButton, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: isDisabled ? 'not-allowed' : 'pointer', position: 'relative', zIndex: 1, } const closeButtonHoverStyle: React.CSSProperties = { ...themeConfig.closeButtonHover, } const closeButtonDisabledStyle: React.CSSProperties = { ...themeConfig.closeButtonDisabled, } return { container: containerStyle, closeButton: closeButtonStyle, closeButtonHover: closeButtonHoverStyle, closeButtonDisabled: closeButtonDisabledStyle, glyph: themeConfig.glyph as React.CSSProperties, glyphLeft: themeConfig.glyphLeft as React.CSSProperties, glyphRight: themeConfig.glyphRight as React.CSSProperties, glyphVisible: themeConfig.glyphVisible as React.CSSProperties, shimmer: themeConfig.shimmer as React.CSSProperties, } }