Component({ options: { virtualHost: true, styleIsolation: 'apply-shared', addGlobalClass: true, }, properties: { name: { type: String, value: '', }, color: { type: String, value: '', }, size: { type: String, value: '', }, classPrefix: { type: String, value: 'toy-icon', }, style: { type: String, value: '', }, }, externalClasses: ['custom-class', 'ext-class'], data: { isImage: false, rootClassName: '', rootStyle: '', fontGlyphClass: '', }, observers: { 'name,color,size,classPrefix,style': function () { this.syncViewState(); }, }, lifetimes: { attached() { this.syncViewState(); }, }, methods: { syncViewState() { const { name, color, size, classPrefix, style } = this.data; const isImage = this.isImageSource(name); const normalizedSize = this.normalizeUnit(size); const classNames = ['toy-icon-root']; let fontGlyphClass = ''; if (isImage) { classNames.push('toy-icon-root--image'); } else { const parts: string[] = []; if (classPrefix) { parts.push(classPrefix); } if (name) { parts.push(`${classPrefix}-${name}`); } fontGlyphClass = parts.join(' '); } const styleSegments = [style]; if (normalizedSize) { styleSegments.push(`font-size:${normalizedSize}`); styleSegments.push(`width:${normalizedSize}`); styleSegments.push(`height:${normalizedSize}`); } if (color && !isImage) { styleSegments.push(`color:${color}`); } this.setData({ isImage, rootClassName: classNames.join(' '), rootStyle: styleSegments.filter(Boolean).join(';'), fontGlyphClass, }); }, isImageSource(name: string) { return /^(https?:\/\/|data:|\/|\.{1,2}\/)/.test(name); }, normalizeUnit(value: string) { if (!value) { return ''; } return /^\d+(\.\d+)?$/.test(value) ? `${value}rpx` : value; }, }, });