import { DeesElement, html, property, customElement, css, type TemplateResult, } from '@design.estate/dees-element'; import * as lucideIcons from 'lucide'; import { Activity, ArrowUp, Bell, Bolt, Box, Building2, Check, ChevronDown, ChevronRight, Clock, Cloud, Copy, CreditCard, Fingerprint, Globe, Grid2x2, Home, Key, Laptop, Lock, LogOut, Mail, MapPin, Monitor, MonitorSmartphone, Nfc, Phone, Plus, Power, QrCode, Search, Settings, Shield, SmartphoneNfc, SquarePen, Trash2, TriangleAlert, User, Users, Wallet, X, createElement, type IconNode, } from 'lucide'; import { idpElementStyles } from './tokens.js'; export type TIdpIconName = | 'activity' | 'alert' | 'alert-triangle' | 'arrow-up' | 'bell' | 'bolt' | 'box' | 'building' | 'building2' | 'building-2' | 'check' | 'chevron' | 'chevron-down' | 'chevron-right' | 'clock' | 'cloud' | 'copy' | 'credit' | 'device' | 'edit' | 'fingerprint' | 'gear' | 'globe' | 'grid' | 'home' | 'key' | 'laptop' | 'location' | 'lock' | 'logout' | 'mail' | 'monitor' | 'monitor-smartphone' | 'nfc' | 'phone' | 'plus' | 'power' | 'qr' | 'search' | 'settings' | 'shield' | 'smartphone-nfc' | 'trash' | 'user' | 'users' | 'wallet' | 'waveform' | 'x' | `lucide:${string}`; declare global { interface HTMLElementTagNameMap { 'idp-icon': IdpIcon; } } const iconNodes: Record = { activity: Activity, alert: TriangleAlert, 'alert-triangle': TriangleAlert, 'arrow-up': ArrowUp, bell: Bell, bolt: Bolt, box: Box, building: Building2, building2: Building2, 'building-2': Building2, check: Check, chevron: ChevronRight, 'chevron-down': ChevronDown, 'chevron-right': ChevronRight, clock: Clock, cloud: Cloud, copy: Copy, credit: CreditCard, device: MonitorSmartphone, edit: SquarePen, fingerprint: Fingerprint, gear: Settings, globe: Globe, grid: Grid2x2, home: Home, key: Key, laptop: Laptop, location: MapPin, lock: Lock, logout: LogOut, mail: Mail, monitor: Monitor, 'monitor-smartphone': MonitorSmartphone, nfc: Nfc, phone: Phone, plus: Plus, power: Power, qr: QrCode, search: Search, settings: Settings, shield: Shield, 'smartphone-nfc': SmartphoneNfc, trash: Trash2, user: User, users: Users, wallet: Wallet, waveform: Activity, x: X, }; const toKebab = (valueArg: string): string => valueArg .replace(/^lucide:/, '') .replace(/([a-z0-9])([A-Z])/g, '$1-$2') .toLowerCase(); const toLucideExportName = (valueArg: string): string => valueArg .replace(/^lucide:/i, '') .split(/[-_: ]+/) .filter(Boolean) .map((partArg) => `${partArg.charAt(0).toUpperCase()}${partArg.slice(1)}`) .join(''); @customElement('idp-icon') export class IdpIcon extends DeesElement { public static demo = () => html``; public static demoGroups = ['idp.global v3 primitives']; @property({ type: String }) public accessor name: TIdpIconName = 'shield'; @property({ type: Number }) public accessor size = 18; private lastRenderKey = ''; public static styles = [ ...idpElementStyles, css` :host { display: inline-flex; align-items: center; justify-content: center; color: currentColor; line-height: 0; vertical-align: middle; } #iconContainer { width: var(--icon-size); height: var(--icon-size); } #iconContainer svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; } `, ]; private resolveIconNode(): IconNode { const rawName = String(this.name || 'shield'); const iconName = toKebab(rawName); const aliasNode = iconNodes[iconName]; if (aliasNode) { return aliasNode; } const exportName = toLucideExportName(rawName); const lucideNode = (lucideIcons as Record)[exportName]; if (Array.isArray(lucideNode)) { return lucideNode as IconNode; } return Shield; } public render(): TemplateResult { return html`
`; } public updated(): void { const renderKey = `${this.name}:${this.size}`; if (this.lastRenderKey === renderKey) { return; } this.lastRenderKey = renderKey; const container = this.shadowRoot?.querySelector('#iconContainer'); if (!container) { return; } container.innerHTML = ''; const iconElement = createElement(this.resolveIconNode(), { color: 'currentColor', size: this.size, strokeWidth: 1.75, }); iconElement.setAttribute('aria-hidden', 'true'); container.appendChild(iconElement); } }