import { LitElement, html, css } from 'lit'; import { property } from 'lit/decorators.js'; export class Icon extends LitElement { @property({ type: String }) name = ''; @property({ type: String }) size: 'small' | 'medium' | 'large' | string = 'medium'; @property({ type: String }) color: 'inherit' | 'primary' | 'secondary' | 'action' | 'disabled' | 'error' = 'inherit'; static styles = css` :host { display: inline-flex; align-items: center; justify-content: center; user-select: none; flex-shrink: 0; } .icon { display: flex; align-items: center; justify-content: center; fill: currentColor; transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; } /* Size variants */ :host([size="small"]) .icon { width: 20px; height: 20px; font-size: 1.25rem; } :host([size="medium"]) .icon, :host(:not([size])) .icon { width: 24px; height: 24px; font-size: 1.5rem; } :host([size="large"]) .icon { width: 32px; height: 32px; font-size: 2rem; } /* Custom size */ :host([size]:not([size="small"]):not([size="medium"]):not([size="large"])) .icon { width: var(--icon-size); height: var(--icon-size); font-size: var(--icon-size); } /* Color variants */ :host([color="inherit"]) .icon, :host(:not([color])) .icon { color: inherit; } :host([color="primary"]) .icon { color: #1976d2; } :host([color="secondary"]) .icon { color: #9c27b0; } :host([color="action"]) .icon { color: rgba(0, 0, 0, 0.54); } :host([color="disabled"]) .icon { color: rgba(0, 0, 0, 0.26); } :host([color="error"]) .icon { color: #d32f2f; } svg { width: 100%; height: 100%; fill: currentColor; } `; connectedCallback() { super.connectedCallback(); this.updateCustomSize(); } updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('size')) { this.updateCustomSize(); } } private updateCustomSize() { if (this.size && !['small', 'medium', 'large'].includes(this.size)) { const sizeValue = this.size.includes('px') || this.size.includes('rem') || this.size.includes('em') ? this.size : `${this.size}px`; this.style.setProperty('--icon-size', sizeValue); } else { this.style.removeProperty('--icon-size'); } } private getIconSvg(name: string): string { const icons: Record = { // Navigation 'menu': '', 'close': '', 'arrow-back': '', 'arrow-forward': '', 'arrow-upward': '', 'arrow-downward': '', 'expand-more': '', 'expand-less': '', 'chevron-left': '', 'chevron-right': '', // Actions 'add': '', 'remove': '', 'edit': '', 'delete': '', 'save': '', 'search': '', 'refresh': '', 'more-vert': '', 'more-horiz': '', // Content 'content-copy': '', 'content-cut': '', 'content-paste': '', // Communication 'call': '', 'chat': '', 'email': '', 'message': '', // File 'folder': '', 'folder-open': '', 'insert-drive-file': '', 'attachment': '', // Device 'phone': '', 'computer': '', 'tablet': '', // Image 'image': '', 'photo-camera': '', 'photo-library': '', // AV 'play-arrow': '', 'pause': '', 'stop': '', 'skip-previous': '', 'skip-next': '', 'volume-up': '', 'volume-off': '', // Social 'person': '', 'people': '', 'group': '', // Places 'home': '', 'location-on': '', 'place': '', // Toggle 'star': '', 'star-border': '', 'favorite': '', 'favorite-border': '', // Hardware 'keyboard': '', 'mouse': '', // Notification 'notifications': '', 'notifications-off': '', // Alert 'warning': '', 'error': '', 'info': '', 'check-circle': '', // Editor 'format-bold': '', 'format-italic': '', 'format-underlined': '', // Maps 'directions': '', 'my-location': '', // Settings 'settings': '', 'tune': '', // Shopping 'shopping-cart': '', 'add-shopping-cart': '', // Date & Time 'access-time': '', 'today': '', 'date-range': '', // Default fallback 'help': '' }; return icons[name] || icons['help']; } render() { if (!this.name) { return html``; } return html`
${html([this.getIconSvg(this.name)] as any)}
`; } }