update
This commit is contained in:
163
ts_web/elements/sio-icon.ts
Normal file
163
ts_web/elements/sio-icon.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
DeesElement,
|
||||
html,
|
||||
property,
|
||||
customElement,
|
||||
cssManager,
|
||||
css,
|
||||
type TemplateResult,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import * as lucideIcons from 'lucide';
|
||||
import { createElement } from 'lucide';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sio-icon': SioIcon;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('sio-icon')
|
||||
export class SioIcon extends DeesElement {
|
||||
public static demo = () => html`
|
||||
<div style="display: flex; gap: 16px; align-items: center;">
|
||||
<sio-icon icon="search"></sio-icon>
|
||||
<sio-icon icon="message-square" color="#3b82f6"></sio-icon>
|
||||
<sio-icon icon="x" size="32"></sio-icon>
|
||||
<sio-icon icon="send" strokeWidth="3"></sio-icon>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@property({ type: String })
|
||||
public icon: string;
|
||||
|
||||
@property({ type: Number })
|
||||
public size: number = 24;
|
||||
|
||||
@property({ type: String })
|
||||
public color: string = 'currentColor';
|
||||
|
||||
@property({ type: Number })
|
||||
public strokeWidth: number = 2;
|
||||
|
||||
// Cache for rendered icons
|
||||
private static iconCache = new Map<string, string>();
|
||||
private static readonly MAX_CACHE_SIZE = 100;
|
||||
|
||||
// Track last rendered properties to avoid unnecessary updates
|
||||
private lastIcon: string | null = null;
|
||||
private lastSize: number | null = null;
|
||||
private lastColor: string | null = null;
|
||||
private lastStrokeWidth: number | null = null;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#iconContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#iconContainer svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div id="iconContainer" style="width: ${this.size}px; height: ${this.size}px;"></div>
|
||||
`;
|
||||
}
|
||||
|
||||
public updated() {
|
||||
// Check if we need to update
|
||||
if (
|
||||
this.lastIcon === this.icon &&
|
||||
this.lastSize === this.size &&
|
||||
this.lastColor === this.color &&
|
||||
this.lastStrokeWidth === this.strokeWidth
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update tracking properties
|
||||
this.lastIcon = this.icon;
|
||||
this.lastSize = this.size;
|
||||
this.lastColor = this.color;
|
||||
this.lastStrokeWidth = this.strokeWidth;
|
||||
|
||||
const container = this.shadowRoot?.querySelector('#iconContainer') as HTMLElement;
|
||||
if (!container || !this.icon) return;
|
||||
|
||||
// Clear container
|
||||
container.innerHTML = '';
|
||||
|
||||
// Create cache key
|
||||
const cacheKey = `${this.icon}:${this.size}:${this.color}:${this.strokeWidth}`;
|
||||
|
||||
// Check cache
|
||||
if (SioIcon.iconCache.has(cacheKey)) {
|
||||
container.innerHTML = SioIcon.iconCache.get(cacheKey)!;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Convert icon name to PascalCase (e.g., 'message-square' -> 'MessageSquare')
|
||||
const pascalCaseName = this.icon
|
||||
.split('-')
|
||||
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
||||
.join('');
|
||||
|
||||
const iconComponent = (lucideIcons as any)[pascalCaseName];
|
||||
if (!iconComponent) {
|
||||
console.warn(`Lucide icon '${pascalCaseName}' not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the icon element
|
||||
const svgElement = createElement(iconComponent, {
|
||||
size: this.size,
|
||||
color: this.color,
|
||||
strokeWidth: this.strokeWidth,
|
||||
});
|
||||
|
||||
if (svgElement) {
|
||||
// Cache the result
|
||||
const svgString = svgElement.outerHTML;
|
||||
SioIcon.iconCache.set(cacheKey, svgString);
|
||||
|
||||
// Limit cache size
|
||||
if (SioIcon.iconCache.size > SioIcon.MAX_CACHE_SIZE) {
|
||||
const firstKey = SioIcon.iconCache.keys().next().value;
|
||||
SioIcon.iconCache.delete(firstKey);
|
||||
}
|
||||
|
||||
// Append to container
|
||||
container.appendChild(svgElement);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error rendering icon ${this.icon}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
public async disconnectedCallback() {
|
||||
await super.disconnectedCallback();
|
||||
// Clear references
|
||||
this.lastIcon = null;
|
||||
this.lastSize = null;
|
||||
this.lastColor = null;
|
||||
this.lastStrokeWidth = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user