@symbo.ls/utils 2.27.16 → 2.28.1
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/dist/cjs/index.js +64 -10
- package/dist/cjs/load.js +62 -5
- package/package.json +3 -3
- package/src/index.js +25 -22
- package/src/load.js +144 -13
package/dist/cjs/index.js
CHANGED
|
@@ -33,6 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
loadJavascriptFile: () => loadJavascriptFile,
|
|
34
34
|
loadJavascriptFileEmbedSync: () => loadJavascriptFileEmbedSync,
|
|
35
35
|
loadJavascriptFileSync: () => loadJavascriptFileSync,
|
|
36
|
+
loadRemoteCSS: () => loadRemoteCSS,
|
|
37
|
+
loadRemoteScript: () => loadRemoteScript,
|
|
36
38
|
removeChars: () => removeChars,
|
|
37
39
|
toCamelCase: () => toCamelCase,
|
|
38
40
|
toDashCase: () => toDashCase,
|
|
@@ -116,10 +118,12 @@ var loadJavascriptFile = (FILE_URL, async = false, doc = document, type = "text/
|
|
|
116
118
|
});
|
|
117
119
|
});
|
|
118
120
|
scriptEle.addEventListener("error", (ev) => {
|
|
119
|
-
reject(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
reject(
|
|
122
|
+
new Error({
|
|
123
|
+
status: false,
|
|
124
|
+
message: `Failed to load the script ${FILE_URL}`
|
|
125
|
+
})
|
|
126
|
+
);
|
|
123
127
|
});
|
|
124
128
|
doc.body.appendChild(scriptEle);
|
|
125
129
|
} catch (error) {
|
|
@@ -190,6 +194,59 @@ var loadJavascript = (body, async = false, doc = document, type = "text/javascri
|
|
|
190
194
|
console.warn(error);
|
|
191
195
|
}
|
|
192
196
|
};
|
|
197
|
+
function loadRemoteScript(url, options = {}) {
|
|
198
|
+
const { window: window3 = globalThis } = options;
|
|
199
|
+
const { document: document3 = window3.document } = options;
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
const existingScript = document3.querySelector(`script[src="${url}"]`);
|
|
202
|
+
if (existingScript) {
|
|
203
|
+
return resolve(existingScript);
|
|
204
|
+
}
|
|
205
|
+
const script = document3.createElement("script");
|
|
206
|
+
script.src = url;
|
|
207
|
+
script.async = options.async === true;
|
|
208
|
+
script.type = options.type || "text/javascript";
|
|
209
|
+
if (options.id) script.id = options.id;
|
|
210
|
+
if (options.integrity) script.integrity = options.integrity;
|
|
211
|
+
if (options.crossOrigin) script.crossOrigin = options.crossOrigin;
|
|
212
|
+
script.onload = () => {
|
|
213
|
+
script.onerror = script.onload = null;
|
|
214
|
+
resolve(script);
|
|
215
|
+
};
|
|
216
|
+
script.onerror = () => {
|
|
217
|
+
script.onerror = script.onload = null;
|
|
218
|
+
reject(new Error(`Failed to load script: ${url}`));
|
|
219
|
+
};
|
|
220
|
+
document3.head.appendChild(script);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
async function loadRemoteCSS(url, options = {}) {
|
|
224
|
+
const { window: window3 = globalThis } = options;
|
|
225
|
+
const { document: document3 = window3.document } = options;
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
const existingLink = document3.querySelector(`link[href="${url}"]`);
|
|
228
|
+
if (existingLink) {
|
|
229
|
+
return resolve(existingLink);
|
|
230
|
+
}
|
|
231
|
+
const link = document3.createElement("link");
|
|
232
|
+
link.href = url;
|
|
233
|
+
link.rel = options.rel || "stylesheet";
|
|
234
|
+
link.type = "text/css";
|
|
235
|
+
link.media = options.media || "all";
|
|
236
|
+
if (options.id) link.id = options.id;
|
|
237
|
+
if (options.integrity) link.integrity = options.integrity;
|
|
238
|
+
if (options.crossOrigin) link.crossOrigin = options.crossOrigin;
|
|
239
|
+
link.onload = () => {
|
|
240
|
+
link.onerror = link.onload = null;
|
|
241
|
+
resolve(link);
|
|
242
|
+
};
|
|
243
|
+
link.onerror = () => {
|
|
244
|
+
link.onerror = link.onload = null;
|
|
245
|
+
reject(new Error(`Failed to load stylesheet: ${url}`));
|
|
246
|
+
};
|
|
247
|
+
document3.head.appendChild(link);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
193
250
|
|
|
194
251
|
// src/files.js
|
|
195
252
|
var isPhoto = (format) => ["jpeg", "gif", "jpg", "png", "tiff", "woff"].includes(format);
|
|
@@ -220,12 +277,9 @@ var toCamelCase = (str) => {
|
|
|
220
277
|
return index === 0 ? word.toLowerCase() : word.toUpperCase();
|
|
221
278
|
}).replaceAll(/\s+/g, "");
|
|
222
279
|
};
|
|
223
|
-
var toTitleCase = (str) => str && str.replace(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
|
227
|
-
}
|
|
228
|
-
);
|
|
280
|
+
var toTitleCase = (str) => str && str.replace(/\w\S*/g, (txt) => {
|
|
281
|
+
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
|
282
|
+
});
|
|
229
283
|
var toDashCase = (val) => val.replace(/[^a-zA-Z0-9]/g, " ").trim().toLowerCase().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
230
284
|
var toDescriptionCase = (str = "") => {
|
|
231
285
|
if (typeof str !== "string") return;
|
package/dist/cjs/load.js
CHANGED
|
@@ -24,7 +24,9 @@ __export(load_exports, {
|
|
|
24
24
|
loadJavascript: () => loadJavascript,
|
|
25
25
|
loadJavascriptFile: () => loadJavascriptFile,
|
|
26
26
|
loadJavascriptFileEmbedSync: () => loadJavascriptFileEmbedSync,
|
|
27
|
-
loadJavascriptFileSync: () => loadJavascriptFileSync
|
|
27
|
+
loadJavascriptFileSync: () => loadJavascriptFileSync,
|
|
28
|
+
loadRemoteCSS: () => loadRemoteCSS,
|
|
29
|
+
loadRemoteScript: () => loadRemoteScript
|
|
28
30
|
});
|
|
29
31
|
module.exports = __toCommonJS(load_exports);
|
|
30
32
|
var loadJavascriptFile = (FILE_URL, async = false, doc = document, type = "text/javascript") => {
|
|
@@ -40,10 +42,12 @@ var loadJavascriptFile = (FILE_URL, async = false, doc = document, type = "text/
|
|
|
40
42
|
});
|
|
41
43
|
});
|
|
42
44
|
scriptEle.addEventListener("error", (ev) => {
|
|
43
|
-
reject(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
reject(
|
|
46
|
+
new Error({
|
|
47
|
+
status: false,
|
|
48
|
+
message: `Failed to load the script ${FILE_URL}`
|
|
49
|
+
})
|
|
50
|
+
);
|
|
47
51
|
});
|
|
48
52
|
doc.body.appendChild(scriptEle);
|
|
49
53
|
} catch (error) {
|
|
@@ -114,3 +118,56 @@ var loadJavascript = (body, async = false, doc = document, type = "text/javascri
|
|
|
114
118
|
console.warn(error);
|
|
115
119
|
}
|
|
116
120
|
};
|
|
121
|
+
function loadRemoteScript(url, options = {}) {
|
|
122
|
+
const { window: window2 = globalThis } = options;
|
|
123
|
+
const { document: document2 = window2.document } = options;
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const existingScript = document2.querySelector(`script[src="${url}"]`);
|
|
126
|
+
if (existingScript) {
|
|
127
|
+
return resolve(existingScript);
|
|
128
|
+
}
|
|
129
|
+
const script = document2.createElement("script");
|
|
130
|
+
script.src = url;
|
|
131
|
+
script.async = options.async === true;
|
|
132
|
+
script.type = options.type || "text/javascript";
|
|
133
|
+
if (options.id) script.id = options.id;
|
|
134
|
+
if (options.integrity) script.integrity = options.integrity;
|
|
135
|
+
if (options.crossOrigin) script.crossOrigin = options.crossOrigin;
|
|
136
|
+
script.onload = () => {
|
|
137
|
+
script.onerror = script.onload = null;
|
|
138
|
+
resolve(script);
|
|
139
|
+
};
|
|
140
|
+
script.onerror = () => {
|
|
141
|
+
script.onerror = script.onload = null;
|
|
142
|
+
reject(new Error(`Failed to load script: ${url}`));
|
|
143
|
+
};
|
|
144
|
+
document2.head.appendChild(script);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async function loadRemoteCSS(url, options = {}) {
|
|
148
|
+
const { window: window2 = globalThis } = options;
|
|
149
|
+
const { document: document2 = window2.document } = options;
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const existingLink = document2.querySelector(`link[href="${url}"]`);
|
|
152
|
+
if (existingLink) {
|
|
153
|
+
return resolve(existingLink);
|
|
154
|
+
}
|
|
155
|
+
const link = document2.createElement("link");
|
|
156
|
+
link.href = url;
|
|
157
|
+
link.rel = options.rel || "stylesheet";
|
|
158
|
+
link.type = "text/css";
|
|
159
|
+
link.media = options.media || "all";
|
|
160
|
+
if (options.id) link.id = options.id;
|
|
161
|
+
if (options.integrity) link.integrity = options.integrity;
|
|
162
|
+
if (options.crossOrigin) link.crossOrigin = options.crossOrigin;
|
|
163
|
+
link.onload = () => {
|
|
164
|
+
link.onerror = link.onload = null;
|
|
165
|
+
resolve(link);
|
|
166
|
+
};
|
|
167
|
+
link.onerror = () => {
|
|
168
|
+
link.onerror = link.onload = null;
|
|
169
|
+
reject(new Error(`Failed to load stylesheet: ${url}`));
|
|
170
|
+
};
|
|
171
|
+
document2.head.appendChild(link);
|
|
172
|
+
});
|
|
173
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.28.1",
|
|
4
4
|
"author": "symbo.ls",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"license": "ISC",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@domql/utils": "^2.
|
|
27
|
+
"@domql/utils": "^2.28.1"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "371cc070cdca345fcd7ea73558d336a03c847825"
|
|
30
30
|
}
|
package/src/index.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import { isString, isObject, isArray, isNumber } from '@domql/utils'
|
|
4
4
|
|
|
5
|
-
export * from './browser'
|
|
6
|
-
export * from './scaling'
|
|
7
|
-
export * from './date'
|
|
8
|
-
export * from './fibonacci'
|
|
9
|
-
export * from './load'
|
|
10
|
-
export * from './files'
|
|
5
|
+
export * from './browser.js'
|
|
6
|
+
export * from './scaling.js'
|
|
7
|
+
export * from './date.js'
|
|
8
|
+
export * from './fibonacci.js'
|
|
9
|
+
export * from './load.js'
|
|
10
|
+
export * from './files.js'
|
|
11
11
|
|
|
12
|
-
export const copyStringToClipboard = async
|
|
12
|
+
export const copyStringToClipboard = async str => {
|
|
13
13
|
try {
|
|
14
14
|
await navigator.clipboard.writeText(str)
|
|
15
15
|
} catch (err) {
|
|
@@ -17,7 +17,7 @@ export const copyStringToClipboard = async (str) => {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const copyJavaScriptToClipboard = async
|
|
20
|
+
export const copyJavaScriptToClipboard = async jsCode => {
|
|
21
21
|
try {
|
|
22
22
|
// Create a Blob for the JavaScript code with the 'text/javascript' MIME type
|
|
23
23
|
const blob = new Blob([jsCode], { type: 'text/javascript' })
|
|
@@ -39,24 +39,27 @@ export const removeChars = str => {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export const toCamelCase = str => {
|
|
42
|
-
return str
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
return str
|
|
43
|
+
.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
|
|
44
|
+
return index === 0 ? word.toLowerCase() : word.toUpperCase()
|
|
45
|
+
})
|
|
46
|
+
.replaceAll(/\s+/g, '')
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
export const toTitleCase = str =>
|
|
48
|
-
|
|
49
|
+
export const toTitleCase = str =>
|
|
50
|
+
str &&
|
|
51
|
+
str.replace(/\w\S*/g, txt => {
|
|
49
52
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
|
|
50
|
-
}
|
|
51
|
-
)
|
|
53
|
+
})
|
|
52
54
|
|
|
53
|
-
export const toDashCase = val =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
export const toDashCase = val =>
|
|
56
|
+
val
|
|
57
|
+
.replace(/[^a-zA-Z0-9]/g, ' ') // Replace non-alphanumeric characters with spaces
|
|
58
|
+
.trim() // Remove leading and trailing spaces
|
|
59
|
+
.toLowerCase() // Convert to lowercase
|
|
60
|
+
.replace(/\s+/g, '-') // Replace spaces with dashes
|
|
61
|
+
.replace(/-+/g, '-') // Replace consecutive dashes with a single dash
|
|
62
|
+
.replace(/^-|-$/g, '') // Remove leading and trailing dashes
|
|
60
63
|
|
|
61
64
|
export const toDescriptionCase = (str = '') => {
|
|
62
65
|
if (typeof str !== 'string') return
|
package/src/load.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
export const loadJavascriptFile = (
|
|
3
|
+
export const loadJavascriptFile = (
|
|
4
|
+
FILE_URL,
|
|
5
|
+
async = false,
|
|
6
|
+
doc = document,
|
|
7
|
+
type = 'text/javascript'
|
|
8
|
+
) => {
|
|
4
9
|
return new Promise((resolve, reject) => {
|
|
5
10
|
try {
|
|
6
11
|
const scriptEle = doc.createElement('script')
|
|
@@ -8,17 +13,19 @@ export const loadJavascriptFile = (FILE_URL, async = false, doc = document, type
|
|
|
8
13
|
scriptEle.async = async
|
|
9
14
|
scriptEle.src = FILE_URL
|
|
10
15
|
|
|
11
|
-
scriptEle.addEventListener('load',
|
|
16
|
+
scriptEle.addEventListener('load', ev => {
|
|
12
17
|
resolve({
|
|
13
18
|
status: true
|
|
14
19
|
})
|
|
15
20
|
})
|
|
16
21
|
|
|
17
|
-
scriptEle.addEventListener('error',
|
|
18
|
-
reject(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
scriptEle.addEventListener('error', ev => {
|
|
23
|
+
reject(
|
|
24
|
+
new Error({
|
|
25
|
+
status: false,
|
|
26
|
+
message: `Failed to load the script ${FILE_URL}`
|
|
27
|
+
})
|
|
28
|
+
)
|
|
22
29
|
})
|
|
23
30
|
|
|
24
31
|
doc.body.appendChild(scriptEle)
|
|
@@ -28,7 +35,11 @@ export const loadJavascriptFile = (FILE_URL, async = false, doc = document, type
|
|
|
28
35
|
})
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
export const loadJavascriptFileSync = (
|
|
38
|
+
export const loadJavascriptFileSync = (
|
|
39
|
+
fileUrl,
|
|
40
|
+
doc = document,
|
|
41
|
+
type = 'text/javascript'
|
|
42
|
+
) => {
|
|
32
43
|
return new Promise((resolve, reject) => {
|
|
33
44
|
const scriptEle = doc.createElement('script')
|
|
34
45
|
scriptEle.type = type
|
|
@@ -36,7 +47,8 @@ export const loadJavascriptFileSync = (fileUrl, doc = document, type = 'text/jav
|
|
|
36
47
|
|
|
37
48
|
// Create a blocking overlay
|
|
38
49
|
const blocker = doc.createElement('div')
|
|
39
|
-
blocker.style.cssText =
|
|
50
|
+
blocker.style.cssText =
|
|
51
|
+
'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(255,255,255,0.8);z-index:9999;'
|
|
40
52
|
doc.body.appendChild(blocker)
|
|
41
53
|
|
|
42
54
|
scriptEle.onload = () => {
|
|
@@ -54,7 +66,12 @@ export const loadJavascriptFileSync = (fileUrl, doc = document, type = 'text/jav
|
|
|
54
66
|
})
|
|
55
67
|
}
|
|
56
68
|
|
|
57
|
-
export const loadJavascriptFileEmbedSync = (
|
|
69
|
+
export const loadJavascriptFileEmbedSync = (
|
|
70
|
+
FILE_URL,
|
|
71
|
+
doc = document,
|
|
72
|
+
fallback,
|
|
73
|
+
type = 'text/javascript'
|
|
74
|
+
) => {
|
|
58
75
|
const xhr = new window.XMLHttpRequest()
|
|
59
76
|
xhr.open('GET', FILE_URL, false) // false makes the request synchronous
|
|
60
77
|
xhr.send()
|
|
@@ -70,14 +87,19 @@ export const loadJavascriptFileEmbedSync = (FILE_URL, doc = document, fallback,
|
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
export const loadCssFile = (
|
|
90
|
+
export const loadCssFile = (
|
|
91
|
+
FILE_URL,
|
|
92
|
+
async = false,
|
|
93
|
+
doc = document,
|
|
94
|
+
type = 'text/javascript'
|
|
95
|
+
) => {
|
|
74
96
|
return new Promise((resolve, reject) => {
|
|
75
97
|
try {
|
|
76
98
|
const linkElem = doc.createElement('link')
|
|
77
99
|
linkElem.rel = 'stylesheet'
|
|
78
100
|
linkElem.href = FILE_URL
|
|
79
101
|
|
|
80
|
-
linkElem.addEventListener('load',
|
|
102
|
+
linkElem.addEventListener('load', ev => {
|
|
81
103
|
resolve({
|
|
82
104
|
status: true
|
|
83
105
|
})
|
|
@@ -90,7 +112,13 @@ export const loadCssFile = (FILE_URL, async = false, doc = document, type = 'tex
|
|
|
90
112
|
})
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
export const loadJavascript = (
|
|
115
|
+
export const loadJavascript = (
|
|
116
|
+
body,
|
|
117
|
+
async = false,
|
|
118
|
+
doc = document,
|
|
119
|
+
type = 'text/javascript',
|
|
120
|
+
id = 'smbls-script'
|
|
121
|
+
) => {
|
|
94
122
|
try {
|
|
95
123
|
const scriptEle = doc.createElement('script')
|
|
96
124
|
scriptEle.type = type
|
|
@@ -103,3 +131,106 @@ export const loadJavascript = (body, async = false, doc = document, type = 'text
|
|
|
103
131
|
console.warn(error)
|
|
104
132
|
}
|
|
105
133
|
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Dynamically loads a remote JavaScript file and returns a Promise
|
|
137
|
+
* that resolves when the script has completely loaded or rejects on error.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} url - The URL of the remote JavaScript file to load
|
|
140
|
+
* @param {Object} [options] - Optional configuration
|
|
141
|
+
* @param {string} [options.id] - Optional ID to assign to the script element
|
|
142
|
+
* @param {boolean} [options.async=true] - Whether to load the script asynchronously
|
|
143
|
+
* @param {string} [options.type='text/javascript'] - The type attribute for the script
|
|
144
|
+
* @param {string} [options.integrity] - Optional integrity hash for SRI
|
|
145
|
+
* @param {string} [options.crossOrigin] - Optional crossorigin attribute
|
|
146
|
+
* @return {Promise} A promise that resolves when the script loads or rejects on error
|
|
147
|
+
*/
|
|
148
|
+
export function loadRemoteScript (url, options = {}) {
|
|
149
|
+
const { window = globalThis } = options
|
|
150
|
+
const { document = window.document } = options
|
|
151
|
+
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
// Check if script is already loaded
|
|
154
|
+
const existingScript = document.querySelector(`script[src="${url}"]`)
|
|
155
|
+
if (existingScript) {
|
|
156
|
+
return resolve(existingScript)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Create script element
|
|
160
|
+
const script = document.createElement('script')
|
|
161
|
+
script.src = url
|
|
162
|
+
script.async = options.async === true
|
|
163
|
+
script.type = options.type || 'text/javascript'
|
|
164
|
+
|
|
165
|
+
// Add optional attributes
|
|
166
|
+
if (options.id) script.id = options.id
|
|
167
|
+
if (options.integrity) script.integrity = options.integrity
|
|
168
|
+
if (options.crossOrigin) script.crossOrigin = options.crossOrigin
|
|
169
|
+
|
|
170
|
+
// Setup load and error handlers
|
|
171
|
+
script.onload = () => {
|
|
172
|
+
script.onerror = script.onload = null
|
|
173
|
+
resolve(script)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
script.onerror = () => {
|
|
177
|
+
script.onerror = script.onload = null
|
|
178
|
+
reject(new Error(`Failed to load script: ${url}`))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Append the script to the document head
|
|
182
|
+
document.head.appendChild(script)
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Dynamically loads a remote CSS file and returns a Promise
|
|
188
|
+
* that resolves when the stylesheet has completely loaded or rejects on error.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} url - The URL of the remote CSS file to load
|
|
191
|
+
* @param {Object} [options] - Optional configuration
|
|
192
|
+
* @param {string} [options.id] - Optional ID to assign to the link element
|
|
193
|
+
* @param {string} [options.rel='stylesheet'] - The rel attribute for the link
|
|
194
|
+
* @param {string} [options.media='all'] - The media attribute
|
|
195
|
+
* @param {string} [options.integrity] - Optional integrity hash for SRI
|
|
196
|
+
* @param {string} [options.crossOrigin] - Optional crossorigin attribute
|
|
197
|
+
* @return {Promise} A promise that resolves when the stylesheet loads or rejects on error
|
|
198
|
+
*/
|
|
199
|
+
export async function loadRemoteCSS (url, options = {}) {
|
|
200
|
+
const { window = globalThis } = options
|
|
201
|
+
const { document = window.document } = options
|
|
202
|
+
|
|
203
|
+
return new Promise((resolve, reject) => {
|
|
204
|
+
// Check if stylesheet is already loaded
|
|
205
|
+
const existingLink = document.querySelector(`link[href="${url}"]`)
|
|
206
|
+
if (existingLink) {
|
|
207
|
+
return resolve(existingLink)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Create link element
|
|
211
|
+
const link = document.createElement('link')
|
|
212
|
+
link.href = url
|
|
213
|
+
link.rel = options.rel || 'stylesheet'
|
|
214
|
+
link.type = 'text/css'
|
|
215
|
+
link.media = options.media || 'all'
|
|
216
|
+
|
|
217
|
+
// Add optional attributes
|
|
218
|
+
if (options.id) link.id = options.id
|
|
219
|
+
if (options.integrity) link.integrity = options.integrity
|
|
220
|
+
if (options.crossOrigin) link.crossOrigin = options.crossOrigin
|
|
221
|
+
|
|
222
|
+
// Setup load and error handlers
|
|
223
|
+
link.onload = () => {
|
|
224
|
+
link.onerror = link.onload = null
|
|
225
|
+
resolve(link)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
link.onerror = () => {
|
|
229
|
+
link.onerror = link.onload = null
|
|
230
|
+
reject(new Error(`Failed to load stylesheet: ${url}`))
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Append the link to the document head
|
|
234
|
+
document.head.appendChild(link)
|
|
235
|
+
})
|
|
236
|
+
}
|