@symbo.ls/utils 3.1.2 → 3.2.3

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.
@@ -27,26 +27,37 @@ var detectHeightOnInit = (element, state) => {
27
27
  const heightTimeout = setTimeout(() => {
28
28
  const { props } = element;
29
29
  if (!state.clientHeight) {
30
- const { node: { clientHeight } } = element;
30
+ const {
31
+ node: { clientHeight }
32
+ } = element;
31
33
  if (clientHeight) {
32
34
  state.clientHeight = clientHeight;
33
35
  }
34
36
  }
35
37
  if (state.active) {
36
38
  if (props.height === "auto") return;
37
- element.update({
38
- props: { height: state.clientHeight }
39
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true });
39
+ element.setProps(
40
+ {
41
+ height: state.clientHeight
42
+ },
43
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
44
+ );
40
45
  const setAutoTimeout = setTimeout(() => {
41
- element.update({
42
- props: { height: "auto" }
43
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true });
46
+ element.setProps(
47
+ {
48
+ height: "auto"
49
+ },
50
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
51
+ );
44
52
  clearTimeout(setAutoTimeout);
45
53
  }, 450);
46
54
  } else {
47
- element.update({
48
- props: { height: "0" }
49
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true });
55
+ element.setProps(
56
+ {
57
+ height: "0"
58
+ },
59
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
60
+ );
50
61
  }
51
62
  clearTimeout(heightTimeout);
52
63
  });
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,
@@ -42,11 +44,11 @@ __export(index_exports, {
42
44
  });
43
45
  module.exports = __toCommonJS(index_exports);
44
46
 
45
- // ../../../domql/packages/utils/globals.js
47
+ // ../../../domql/packages/utils/dist/esm/globals.js
46
48
  var window2 = globalThis;
47
49
  var document2 = window2.document;
48
50
 
49
- // ../../../domql/packages/utils/types.js
51
+ // ../../../domql/packages/utils/dist/esm/types.js
50
52
  var isObject = (arg) => {
51
53
  if (arg === null) return false;
52
54
  return typeof arg === "object" && arg.constructor === Object;
@@ -55,7 +57,7 @@ var isString = (arg) => typeof arg === "string";
55
57
  var isNumber = (arg) => typeof arg === "number";
56
58
  var isArray = (arg) => Array.isArray(arg);
57
59
 
58
- // ../../../domql/packages/utils/keys.js
60
+ // ../../../domql/packages/utils/dist/esm/keys.js
59
61
  var STATE_METHODS = [
60
62
  "update",
61
63
  "parse",
@@ -126,7 +128,7 @@ var METHODS_EXL = [
126
128
  ...PROPS_METHODS
127
129
  ];
128
130
 
129
- // ../../../domql/packages/utils/cookie.js
131
+ // ../../../domql/packages/utils/dist/esm/cookie.js
130
132
  var isMobile = (() => typeof navigator === "undefined" ? false : /Mobi/.test(navigator.userAgent))();
131
133
 
132
134
  // ../../../domql/packages/event/dist/esm/keys.js
@@ -262,10 +264,12 @@ var loadJavascriptFile = (FILE_URL, async = false, doc = document, type = "text/
262
264
  });
263
265
  });
264
266
  scriptEle.addEventListener("error", (ev) => {
265
- reject(new Error({
266
- status: false,
267
- message: `Failed to load the script ${FILE_URL}`
268
- }));
267
+ reject(
268
+ new Error({
269
+ status: false,
270
+ message: `Failed to load the script ${FILE_URL}`
271
+ })
272
+ );
269
273
  });
270
274
  doc.body.appendChild(scriptEle);
271
275
  } catch (error) {
@@ -336,6 +340,59 @@ var loadJavascript = (body, async = false, doc = document, type = "text/javascri
336
340
  console.warn(error);
337
341
  }
338
342
  };
343
+ function loadRemoteScript(url, options = {}) {
344
+ const { window: window4 = globalThis } = options;
345
+ const { document: document4 = window4.document } = options;
346
+ return new Promise((resolve, reject) => {
347
+ const existingScript = document4.querySelector(`script[src="${url}"]`);
348
+ if (existingScript) {
349
+ return resolve(existingScript);
350
+ }
351
+ const script = document4.createElement("script");
352
+ script.src = url;
353
+ script.async = options.async === true;
354
+ script.type = options.type || "text/javascript";
355
+ if (options.id) script.id = options.id;
356
+ if (options.integrity) script.integrity = options.integrity;
357
+ if (options.crossOrigin) script.crossOrigin = options.crossOrigin;
358
+ script.onload = () => {
359
+ script.onerror = script.onload = null;
360
+ resolve(script);
361
+ };
362
+ script.onerror = () => {
363
+ script.onerror = script.onload = null;
364
+ reject(new Error(`Failed to load script: ${url}`));
365
+ };
366
+ document4.head.appendChild(script);
367
+ });
368
+ }
369
+ async function loadRemoteCSS(url, options = {}) {
370
+ const { window: window4 = globalThis } = options;
371
+ const { document: document4 = window4.document } = options;
372
+ return new Promise((resolve, reject) => {
373
+ const existingLink = document4.querySelector(`link[href="${url}"]`);
374
+ if (existingLink) {
375
+ return resolve(existingLink);
376
+ }
377
+ const link = document4.createElement("link");
378
+ link.href = url;
379
+ link.rel = options.rel || "stylesheet";
380
+ link.type = "text/css";
381
+ link.media = options.media || "all";
382
+ if (options.id) link.id = options.id;
383
+ if (options.integrity) link.integrity = options.integrity;
384
+ if (options.crossOrigin) link.crossOrigin = options.crossOrigin;
385
+ link.onload = () => {
386
+ link.onerror = link.onload = null;
387
+ resolve(link);
388
+ };
389
+ link.onerror = () => {
390
+ link.onerror = link.onload = null;
391
+ reject(new Error(`Failed to load stylesheet: ${url}`));
392
+ };
393
+ document4.head.appendChild(link);
394
+ });
395
+ }
339
396
 
340
397
  // src/files.js
341
398
  var isPhoto = (format) => ["jpeg", "gif", "jpg", "png", "tiff", "woff"].includes(format);
@@ -366,12 +423,9 @@ var toCamelCase = (str) => {
366
423
  return index === 0 ? word.toLowerCase() : word.toUpperCase();
367
424
  }).replaceAll(/\s+/g, "");
368
425
  };
369
- var toTitleCase = (str) => str && str.replace(
370
- /\w\S*/g,
371
- (txt) => {
372
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
373
- }
374
- );
426
+ var toTitleCase = (str) => str && str.replace(/\w\S*/g, (txt) => {
427
+ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
428
+ });
375
429
  var toDashCase = (val) => val.replace(/[^a-zA-Z0-9]/g, " ").trim().toLowerCase().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
376
430
  var toDescriptionCase = (str = "") => {
377
431
  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(new Error({
44
- status: false,
45
- message: `Failed to load the script ${FILE_URL}`
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
+ }
@@ -25,18 +25,18 @@ __export(scaling_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(scaling_exports);
27
27
 
28
- // ../../../domql/packages/utils/globals.js
28
+ // ../../../domql/packages/utils/dist/esm/globals.js
29
29
  var window2 = globalThis;
30
30
  var document2 = window2.document;
31
31
 
32
- // ../../../domql/packages/utils/types.js
32
+ // ../../../domql/packages/utils/dist/esm/types.js
33
33
  var isObject = (arg) => {
34
34
  if (arg === null) return false;
35
35
  return typeof arg === "object" && arg.constructor === Object;
36
36
  };
37
37
  var isArray = (arg) => Array.isArray(arg);
38
38
 
39
- // ../../../domql/packages/utils/keys.js
39
+ // ../../../domql/packages/utils/dist/esm/keys.js
40
40
  var STATE_METHODS = [
41
41
  "update",
42
42
  "parse",
@@ -107,7 +107,7 @@ var METHODS_EXL = [
107
107
  ...PROPS_METHODS
108
108
  ];
109
109
 
110
- // ../../../domql/packages/utils/cookie.js
110
+ // ../../../domql/packages/utils/dist/esm/cookie.js
111
111
  var isMobile = (() => typeof navigator === "undefined" ? false : /Mobi/.test(navigator.userAgent))();
112
112
 
113
113
  // ../../../domql/packages/event/dist/esm/keys.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/utils",
3
- "version": "3.1.2",
3
+ "version": "3.2.3",
4
4
  "author": "symbo.ls",
5
5
  "files": [
6
6
  "src",
@@ -16,16 +16,16 @@
16
16
  "publishConfig": {},
17
17
  "scripts": {
18
18
  "copy:package:cjs": "cp ../../build/package-cjs.json dist/cjs/package.json",
19
- "build:esm": "npx esbuild ./src/*.js ./src/**/*.js --target=es2017 --format=esm --outdir=dist/esm",
20
- "build:cjs": "npx esbuild ./src/*.js ./src/**/*.js --target=node16 --format=cjs --outdir=dist/cjs --bundle",
21
- "build:iife": "npx esbuild ./src/index.js --target=es2017 --format=iife --outdir=dist/iife --bundle --minify",
19
+ "build:esm": "npx cross-env NODE_ENV=$NODE_ENV npx esbuild ./src/*.js ./src/**/*.js --target=es2017 --format=esm --outdir=dist/esm",
20
+ "build:cjs": "npx cross-env NODE_ENV=$NODE_ENV npx esbuild ./src/*.js ./src/**/*.js --target=node16 --format=cjs --outdir=dist/cjs --bundle",
21
+ "build:iife": "npx cross-env NODE_ENV=$NODE_ENV npx esbuild ./src/index.js --target=es2017 --format=iife --outdir=dist/iife --bundle --minify",
22
22
  "build": "npm run build:cjs",
23
23
  "prepublish": "rimraf -I dist && npm run build && npm run copy:package:cjs"
24
24
  },
25
25
  "license": "ISC",
26
26
  "dependencies": {
27
- "@domql/event": "^3.1.2",
28
- "@domql/utils": "^3.1.2"
27
+ "@domql/event": "^3.2.3",
28
+ "@domql/utils": "^3.2.3"
29
29
  },
30
- "gitHead": "429b36616aa04c8587a26ce3c129815115e35897"
30
+ "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681"
31
31
  }
@@ -4,7 +4,9 @@ export const detectHeightOnInit = (element, state) => {
4
4
  const heightTimeout = setTimeout(() => {
5
5
  const { props } = element
6
6
  if (!state.clientHeight) {
7
- const { node: { clientHeight } } = element
7
+ const {
8
+ node: { clientHeight }
9
+ } = element
8
10
  if (clientHeight) {
9
11
  state.clientHeight = clientHeight
10
12
  }
@@ -12,19 +14,28 @@ export const detectHeightOnInit = (element, state) => {
12
14
 
13
15
  if (state.active) {
14
16
  if (props.height === 'auto') return
15
- element.update({
16
- props: { height: state.clientHeight }
17
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true })
17
+ element.setProps(
18
+ {
19
+ height: state.clientHeight
20
+ },
21
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
22
+ )
18
23
  const setAutoTimeout = setTimeout(() => {
19
- element.update({
20
- props: { height: 'auto' }
21
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true })
24
+ element.setProps(
25
+ {
26
+ height: 'auto'
27
+ },
28
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
29
+ )
22
30
  clearTimeout(setAutoTimeout)
23
31
  }, 450)
24
32
  } else {
25
- element.update({
26
- props: { height: '0' }
27
- }, { preventBeforeUpdateListener: true, preventChildrenUpdate: true })
33
+ element.setProps(
34
+ {
35
+ height: '0'
36
+ },
37
+ { preventBeforeUpdateListener: true, preventChildrenUpdate: true }
38
+ )
28
39
  }
29
40
  clearTimeout(heightTimeout)
30
41
  })
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 (str) => {
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 (jsCode) => {
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.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
43
- return index === 0 ? word.toLowerCase() : word.toUpperCase()
44
- }).replaceAll(/\s+/g, '')
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 => str && str.replace(
48
- /\w\S*/g, txt => {
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 => val
54
- .replace(/[^a-zA-Z0-9]/g, ' ') // Replace non-alphanumeric characters with spaces
55
- .trim() // Remove leading and trailing spaces
56
- .toLowerCase() // Convert to lowercase
57
- .replace(/\s+/g, '-') // Replace spaces with dashes
58
- .replace(/-+/g, '-') // Replace consecutive dashes with a single dash
59
- .replace(/^-|-$/g, '') // Remove leading and trailing dashes
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 = (FILE_URL, async = false, doc = document, type = 'text/javascript') => {
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', (ev) => {
16
+ scriptEle.addEventListener('load', ev => {
12
17
  resolve({
13
18
  status: true
14
19
  })
15
20
  })
16
21
 
17
- scriptEle.addEventListener('error', (ev) => {
18
- reject(new Error({
19
- status: false,
20
- message: `Failed to load the script ${FILE_URL}`
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 = (fileUrl, doc = document, type = 'text/javascript') => {
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 = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(255,255,255,0.8);z-index:9999;'
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 = (FILE_URL, doc = document, fallback, type = 'text/javascript') => {
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 = (FILE_URL, async = false, doc = document, type = 'text/javascript') => {
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', (ev) => {
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 = (body, async = false, doc = document, type = 'text/javascript', id = 'smbls-script') => {
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
+ }