@identitate-md/logos 1.3.7 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/identity-loader.js +49 -39
- package/package.json +1 -1
package/identity-loader.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* IdentitateRO Web Component Loader
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* A custom HTML element for loading Romanian institution logos
|
|
5
5
|
* Framework-agnostic, works with React, Vue, Angular, vanilla HTML, etc.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* <identity-icon src="https://cdn.jsdelivr.net/npm/@identitate-
|
|
9
|
-
*
|
|
8
|
+
* <identity-icon src="https://cdn.jsdelivr.net/npm/@identitate-md/logos@latest/logos/anaf/anaf.svg"></identity-icon>
|
|
9
|
+
*
|
|
10
10
|
* Features:
|
|
11
11
|
* - Automatic SVG fetching and injection
|
|
12
12
|
* - Built-in caching (loads each SVG only once)
|
|
13
13
|
* - CSS styling support (fill: currentColor)
|
|
14
14
|
* - Error handling with fallback display
|
|
15
15
|
* - Observable attributes (dynamic updates)
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* @version 1.0.0
|
|
18
18
|
* @license MIT
|
|
19
19
|
*/
|
|
@@ -38,7 +38,7 @@ class IdentityIcon extends HTMLElement {
|
|
|
38
38
|
* Define which attributes to observe for changes
|
|
39
39
|
*/
|
|
40
40
|
static get observedAttributes() {
|
|
41
|
-
return [
|
|
41
|
+
return ["src", "size"];
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -54,19 +54,23 @@ class IdentityIcon extends HTMLElement {
|
|
|
54
54
|
* Main rendering logic
|
|
55
55
|
*/
|
|
56
56
|
async render() {
|
|
57
|
-
let url = this.getAttribute(
|
|
58
|
-
|
|
57
|
+
let url = this.getAttribute("src");
|
|
58
|
+
|
|
59
59
|
if (!url) {
|
|
60
|
-
this.showError(
|
|
60
|
+
this.showError("Missing src attribute");
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Resolve relative paths to absolute URLs (for local dev / same-origin usage)
|
|
65
|
-
if (
|
|
65
|
+
if (
|
|
66
|
+
!url.startsWith("http://") &&
|
|
67
|
+
!url.startsWith("https://") &&
|
|
68
|
+
!url.startsWith("data:")
|
|
69
|
+
) {
|
|
66
70
|
try {
|
|
67
71
|
url = new URL(url, document.baseURI).href;
|
|
68
72
|
} catch (e) {
|
|
69
|
-
this.showError(
|
|
73
|
+
this.showError("Invalid URL: " + url);
|
|
70
74
|
return;
|
|
71
75
|
}
|
|
72
76
|
}
|
|
@@ -84,15 +88,18 @@ class IdentityIcon extends HTMLElement {
|
|
|
84
88
|
try {
|
|
85
89
|
// Fetch SVG content
|
|
86
90
|
const response = await fetch(url);
|
|
87
|
-
|
|
91
|
+
|
|
88
92
|
if (!response.ok) {
|
|
89
93
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
const contentType = response.headers.get(
|
|
93
|
-
const isSvg =
|
|
96
|
+
const contentType = response.headers.get("content-type") || "";
|
|
97
|
+
const isSvg =
|
|
98
|
+
contentType.includes("svg") ||
|
|
99
|
+
contentType.includes("xml") ||
|
|
100
|
+
url.endsWith(".svg");
|
|
94
101
|
if (!isSvg) {
|
|
95
|
-
throw new Error(
|
|
102
|
+
throw new Error("Response is not an SVG file");
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
const svgContent = await response.text();
|
|
@@ -105,9 +112,8 @@ class IdentityIcon extends HTMLElement {
|
|
|
105
112
|
|
|
106
113
|
// Inject into DOM
|
|
107
114
|
this.injectSvg(cleanedSvg);
|
|
108
|
-
|
|
109
115
|
} catch (error) {
|
|
110
|
-
console.error(
|
|
116
|
+
console.error("[IdentitateRO] Failed to load logo:", url, error);
|
|
111
117
|
this.showError(error.message);
|
|
112
118
|
} finally {
|
|
113
119
|
this._isLoading = false;
|
|
@@ -120,9 +126,9 @@ class IdentityIcon extends HTMLElement {
|
|
|
120
126
|
sanitizeSvg(svgContent) {
|
|
121
127
|
// Remove script tags and event handlers
|
|
122
128
|
return svgContent
|
|
123
|
-
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
|
124
|
-
.replace(/on\w+="[^"]*"/gi,
|
|
125
|
-
.replace(/on\w+='[^']*'/gi,
|
|
129
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
|
|
130
|
+
.replace(/on\w+="[^"]*"/gi, "")
|
|
131
|
+
.replace(/on\w+='[^']*'/gi, "");
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
/**
|
|
@@ -132,32 +138,36 @@ class IdentityIcon extends HTMLElement {
|
|
|
132
138
|
this.innerHTML = svgContent;
|
|
133
139
|
|
|
134
140
|
// Configure SVG element for CSS styling
|
|
135
|
-
const svg = this.querySelector(
|
|
141
|
+
const svg = this.querySelector("svg");
|
|
136
142
|
if (svg) {
|
|
137
143
|
// Make SVG responsive
|
|
138
|
-
svg.setAttribute(
|
|
139
|
-
svg.setAttribute(
|
|
140
|
-
|
|
144
|
+
svg.setAttribute("width", "100%");
|
|
145
|
+
svg.setAttribute("height", "100%");
|
|
146
|
+
|
|
141
147
|
// Enable CSS color control
|
|
142
|
-
svg.style.fill =
|
|
143
|
-
|
|
148
|
+
svg.style.fill = "currentColor";
|
|
149
|
+
|
|
144
150
|
// Preserve aspect ratio
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
svg.
|
|
151
|
+
if (
|
|
152
|
+
!svg.hasAttribute("viewBox") &&
|
|
153
|
+
svg.hasAttribute("width") &&
|
|
154
|
+
svg.hasAttribute("height")
|
|
155
|
+
) {
|
|
156
|
+
const width = svg.getAttribute("width");
|
|
157
|
+
const height = svg.getAttribute("height");
|
|
158
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
149
159
|
}
|
|
150
160
|
|
|
151
161
|
// Apply size attribute if present
|
|
152
|
-
const size = this.getAttribute(
|
|
162
|
+
const size = this.getAttribute("size");
|
|
153
163
|
if (size) {
|
|
154
164
|
this.style.width = size;
|
|
155
165
|
this.style.height = size;
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
// Ensure display is set
|
|
159
|
-
if (!this.style.display || this.style.display ===
|
|
160
|
-
this.style.display =
|
|
169
|
+
if (!this.style.display || this.style.display === "") {
|
|
170
|
+
this.style.display = "inline-block";
|
|
161
171
|
}
|
|
162
172
|
}
|
|
163
173
|
}
|
|
@@ -167,7 +177,7 @@ class IdentityIcon extends HTMLElement {
|
|
|
167
177
|
*/
|
|
168
178
|
showLoading() {
|
|
169
179
|
this.innerHTML = `<span style="opacity: 0.5; font-size: 0.75em;">⏳</span>`;
|
|
170
|
-
this.setAttribute(
|
|
180
|
+
this.setAttribute("aria-busy", "true");
|
|
171
181
|
}
|
|
172
182
|
|
|
173
183
|
/**
|
|
@@ -175,17 +185,17 @@ class IdentityIcon extends HTMLElement {
|
|
|
175
185
|
*/
|
|
176
186
|
showError(message) {
|
|
177
187
|
this.innerHTML = `<span style="opacity: 0.5; font-size: 0.75em;" title="${message}">⚠️</span>`;
|
|
178
|
-
this.setAttribute(
|
|
179
|
-
this.removeAttribute(
|
|
188
|
+
this.setAttribute("aria-invalid", "true");
|
|
189
|
+
this.removeAttribute("aria-busy");
|
|
180
190
|
}
|
|
181
191
|
}
|
|
182
192
|
|
|
183
193
|
// Register the custom element
|
|
184
|
-
if (!customElements.get(
|
|
185
|
-
customElements.define(
|
|
194
|
+
if (!customElements.get("identity-icon")) {
|
|
195
|
+
customElements.define("identity-icon", IdentityIcon);
|
|
186
196
|
}
|
|
187
197
|
|
|
188
198
|
// Export for module environments
|
|
189
|
-
if (typeof module !==
|
|
199
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
190
200
|
module.exports = IdentityIcon;
|
|
191
201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@identitate-md/logos",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "Logo-uri oficiale ale instituțiilor publice din Republica Moldova — Official logos of public institutions from the Republic of Moldova",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "IdentitateMD Contributors",
|