@cloudparker/moldex.js 0.0.50 → 0.0.52

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.
Files changed (50) hide show
  1. package/dist/services/dialog/dialog-service.d.ts +27 -0
  2. package/dist/services/dialog/dialog-service.js +110 -0
  3. package/dist/services/index.d.ts +6 -0
  4. package/dist/services/index.js +6 -1
  5. package/dist/services/navigation/navigation-service.js +5 -5
  6. package/dist/services/utils/color-service.d.ts +46 -0
  7. package/dist/services/utils/color-service.js +73 -0
  8. package/dist/services/utils/download-service.d.ts +91 -0
  9. package/dist/services/utils/download-service.js +159 -0
  10. package/dist/services/utils/file-service.d.ts +138 -0
  11. package/dist/services/utils/file-service.js +258 -0
  12. package/dist/services/utils/http-service.d.ts +77 -0
  13. package/dist/services/utils/http-service.js +158 -0
  14. package/dist/services/utils/image-service.d.ts +81 -0
  15. package/dist/services/utils/image-service.js +194 -0
  16. package/dist/services/utils/utils-service.d.ts +257 -55
  17. package/dist/services/utils/utils-service.js +347 -327
  18. package/dist/tailwind.css +1 -1
  19. package/dist/views/core/index.js +0 -1
  20. package/dist/views/core/input/components/color-field/color-field.svelte +2 -2
  21. package/dist/views/core/input/components/color-field/color-field.svelte.d.ts +2 -11
  22. package/dist/views/core/input/components/combobox-field/combobox-field.svelte +2 -2
  23. package/dist/views/core/input/components/date-field/date-field.svelte +1 -1
  24. package/dist/views/core/input/components/date-field/date-field.svelte.d.ts +1 -10
  25. package/dist/views/core/input/components/datetime-field/datetime-field.svelte +1 -1
  26. package/dist/views/core/input/components/datetime-field/datetime-field.svelte.d.ts +1 -10
  27. package/dist/views/core/input/components/email-field/email-field.svelte +1 -1
  28. package/dist/views/core/input/components/email-field/email-field.svelte.d.ts +1 -10
  29. package/dist/views/core/input/components/file-field/file-field.svelte +15 -8
  30. package/dist/views/core/input/components/file-field/file-field.svelte.d.ts +2 -11
  31. package/dist/views/core/input/components/number-field/number-field.svelte +1 -1
  32. package/dist/views/core/input/components/number-field/number-field.svelte.d.ts +1 -10
  33. package/dist/views/core/input/components/password-field/password-field.svelte +1 -1
  34. package/dist/views/core/input/components/password-field/password-field.svelte.d.ts +1 -10
  35. package/dist/views/core/input/components/phone-field/phone-field.svelte +1 -1
  36. package/dist/views/core/input/components/phone-field/phone-field.svelte.d.ts +1 -10
  37. package/dist/views/core/input/components/search-field/search-field.svelte +1 -1
  38. package/dist/views/core/input/components/search-field/search-field.svelte.d.ts +1 -10
  39. package/dist/views/core/input/components/text-field/text-field.svelte +1 -1
  40. package/dist/views/core/input/components/text-field/text-field.svelte.d.ts +2 -11
  41. package/dist/views/core/input/components/textarea-field/textarea-field.svelte +1 -1
  42. package/dist/views/core/input/components/textarea-field/textarea-field.svelte.d.ts +2 -11
  43. package/dist/views/core/input/components/time-field/time-field.svelte +1 -1
  44. package/dist/views/core/input/components/time-field/time-field.svelte.d.ts +2 -11
  45. package/dist/views/core/text/components/text-copy/text-copy.svelte +3 -3
  46. package/package.json +2 -2
  47. package/dist/views/core/referrer/components/referrer.svelte +0 -16
  48. package/dist/views/core/referrer/components/referrer.svelte.d.ts +0 -18
  49. package/dist/views/core/referrer/index.d.ts +0 -2
  50. package/dist/views/core/referrer/index.js +0 -2
@@ -1,158 +1,52 @@
1
- import { BROWSER } from 'esm-env';
2
1
  import { toDate } from '../date/date-service';
3
- const KEY_GEO_INFO = 'geo.info';
4
- export const FILE_VIEWER_HOST = 'https://viewer.cloudparker.com';
5
- export const CODE_FILE_EXTENTIONS = [
6
- "java", "js", "ts", "json", "c", "cpp", "cs", "py", "ts", "php", "rb", "swift", "go",
7
- "rs", "kt", "scala", "pl", "lua", "hs", "sh", "ps1", "dart", "jl", "m", "f90", "txt",
8
- "r", "groovy", "asm", "pas", "ada", "sql", "md", "html", "css", "xml", "yaml", "xml",
9
- "bat",
10
- ];
11
- export const ACCEPT_IMAGE_FILES = ".png,.PNG,.jpg,.jpg,.jepg,.JPEG,.webp,.WEBP";
2
+ /**
3
+ * Generates a random number between the specified minimum and maximum values (inclusive of the minimum and exclusive of the maximum).
4
+ *
5
+ * @param min - The minimum value (inclusive) of the random number range.
6
+ * @param max - The maximum value (exclusive) of the random number range.
7
+ * @returns A random number between `min` (inclusive) and `max` (exclusive).
8
+ *
9
+ * @example
10
+ * // Generate a random number between 1 (inclusive) and 5 (exclusive)
11
+ * const randomNumber = random(1, 5); // Possible values: 1.0, 2.4, 3.6, etc.
12
+ *
13
+ * @example
14
+ * // Generate a random number between 10 (inclusive) and 20 (exclusive)
15
+ * const randomNumber = random(10, 20); // Possible values: 10.0, 15.3, 19.8, etc.
16
+ */
12
17
  export function random(min, max) {
18
+ if (min >= max) {
19
+ throw new Error('The "max" value must be greater than the "min" value.');
20
+ }
13
21
  return min + Math.random() * (max - min);
14
22
  }
15
- export function openFilePicker(opt) {
16
- return new Promise(resolve => {
17
- let input = document.createElement('input');
18
- input.type = 'file';
19
- input.multiple = opt.multiple || false;
20
- input.accept = opt.accept || ACCEPT_IMAGE_FILES;
21
- input.onchange = _ => {
22
- let files = Array.from(input.files);
23
- if (opt.multiple) {
24
- resolve(files);
25
- }
26
- else {
27
- resolve(files[0]);
28
- }
29
- document.body.removeChild(input);
30
- };
31
- input.style.display = 'none';
32
- document.body.appendChild(input);
33
- input.click();
34
- });
35
- }
36
23
  /**
37
- * Default quality 1.0
38
- * @param opt
39
- * @returns
24
+ * Strips the Base64 content from a Data URL string.
25
+ *
26
+ * This function removes the `data:[<mediatype>][;base64],` prefix from a Data URL string,
27
+ * leaving only the Base64 content. If the input is not a valid Data URL, the original input is returned.
28
+ *
29
+ * @param dataUrl - The Data URL string to be stripped.
30
+ * @returns The stripped Base64 content, or the original string if it is not a valid Data URL.
31
+ *
32
+ * @example
33
+ * // Remove the prefix from a Data URL string
34
+ * const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...';
35
+ * const base64Content = stripDataUrl(dataUrl);
36
+ * console.log(base64Content); // Output: "iVBORw0KGgoAAAANSUhEUgAA..."
40
37
  */
41
- export function resizeImage(opt) {
42
- return new Promise((resolve, reject) => {
43
- const reader = new FileReader();
44
- reader.readAsDataURL(opt.file);
45
- reader.onload = (event) => {
46
- const img = new Image();
47
- img.src = event.target.result;
48
- img.onload = () => {
49
- const elem = document.createElement('canvas');
50
- let width = opt.width;
51
- let height = opt.height || opt.width;
52
- elem.width = width;
53
- elem.height = height;
54
- const ctx = elem.getContext('2d');
55
- if (ctx) {
56
- ctx.drawImage(img, 0, 0, width, height);
57
- ctx.canvas.toBlob((blob) => {
58
- const f = new File([blob], opt.fileName || opt.file
59
- .name, {
60
- type: opt.type || 'image/webp',
61
- lastModified: Date.now()
62
- });
63
- resolve(f);
64
- }, opt.type || 'image/webp', opt.quality ? (opt.quality / 100) : 0.8);
65
- }
66
- },
67
- reader.onerror = error => console.log(error);
68
- };
69
- });
70
- }
71
- export async function downloadURI(uri, name) {
72
- const res = await fetch(uri);
73
- const link = document.createElement("a");
74
- link.download = name;
75
- link.href = URL.createObjectURL(await res.blob());
76
- document.body.appendChild(link);
77
- link.click();
78
- document.body.removeChild(link);
79
- }
80
- export async function downloadFile(file) {
81
- const link = document.createElement("a");
82
- link.download = file.name;
83
- link.href = URL.createObjectURL(file);
84
- document.body.appendChild(link);
85
- link.click();
86
- document.body.removeChild(link);
87
- }
88
- export function downloadBlob(blob, name) {
89
- return downloadFile(new File([blob], name));
90
- }
91
- export async function fileToDataURL(file) {
92
- return new Promise((resolve, reject) => {
93
- const reader = new FileReader();
94
- reader.onloadend = function () {
95
- const base64data = reader.result;
96
- //console.log(base64data);
97
- resolve(base64data);
98
- };
99
- reader.readAsDataURL(file);
100
- });
101
- }
102
- export async function fileToText(file) {
103
- return new Promise((resolve, reject) => {
104
- const reader = new FileReader();
105
- reader.onloadend = function () {
106
- const text = reader.result;
107
- //console.log(base64data);
108
- resolve(text);
109
- };
110
- reader.readAsText(file);
111
- });
112
- }
113
- export async function fileToBuffer(file) {
114
- return new Promise((resolve, reject) => {
115
- const reader = new FileReader();
116
- reader.onloadend = function () {
117
- resolve(reader.result);
118
- };
119
- reader.readAsArrayBuffer(file);
120
- });
121
- }
122
- export async function fileToImage(file) {
123
- return new Promise((resolve, reject) => {
124
- const reader = new FileReader();
125
- reader.onloadend = () => {
126
- var imgObj = new Image();
127
- imgObj.src = reader.result;
128
- imgObj.onload = () => {
129
- resolve(imgObj);
130
- };
131
- };
132
- reader.readAsDataURL(file);
133
- });
134
- }
135
- export async function dataUrlToImage(base64) {
136
- return new Promise((resolve, reject) => {
137
- var imgObj = new Image();
138
- imgObj.src = base64;
139
- imgObj.onload = () => {
140
- resolve(imgObj);
141
- };
142
- });
143
- }
144
- export function stripBase64(data) {
145
- if (data) {
146
- return data.split(',')[1];
38
+ export function stripDataUrl(dataUrl) {
39
+ if (typeof dataUrl === 'string' && dataUrl.startsWith('data:')) {
40
+ return dataUrl.split(',')[1] || '';
147
41
  }
148
- return data;
42
+ return dataUrl;
149
43
  }
150
44
  /**
151
45
  * Function to download content from a given URL and convert it to a Base64-encoded string.
152
46
  * @param url - The URL to download the content from.
153
47
  * @returns A promise that resolves to the Base64-encoded string of the downloaded content.
154
48
  */
155
- export async function urlToBase64(url) {
49
+ export async function readUrlAsBase64(url) {
156
50
  try {
157
51
  const response = await fetch(url);
158
52
  if (!response.ok) {
@@ -168,232 +62,358 @@ export async function urlToBase64(url) {
168
62
  throw error;
169
63
  }
170
64
  }
171
- export function urlToFile(url, givenFileName, givenMimeType) {
172
- return dataUrlToFile(url, givenFileName, givenMimeType);
65
+ /**
66
+ * Validates if a given string is a valid email address.
67
+ *
68
+ * This function uses a regular expression to validate email addresses based on common patterns.
69
+ *
70
+ * @param email - The email address string to validate.
71
+ * @returns A boolean indicating whether the email is valid.
72
+ *
73
+ * @example
74
+ * const isValid = isValidEmailAddress('test@example.com');
75
+ * console.log(isValid); // Output: true
76
+ */
77
+ export function isValidEmailAddress(email) {
78
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
79
+ return emailPattern.test(email.toLowerCase());
173
80
  }
174
- export function dataUrlToFile(url, givenFileName, givenMimeType) {
175
- return (fetch(url)
176
- .then(async (res) => {
177
- // Get Content-Disposition header and extract filename
178
- const contentDisposition = res.headers.get('Content-Disposition');
179
- let fileName = "";
180
- if (contentDisposition) {
181
- // Try to extract filename from the Content-Disposition header
182
- const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
183
- if (filenameMatch && filenameMatch[1]) {
184
- fileName = filenameMatch[1].replace(/['"]/g, '');
81
+ /**
82
+ * Validates if a given string is a valid URL.
83
+ *
84
+ * This function uses a regular expression to validate URLs based on common URL patterns.
85
+ *
86
+ * @param url - The URL string to validate.
87
+ * @returns A boolean indicating whether the URL is valid.
88
+ *
89
+ * @example
90
+ * const isValid = isValidUrl('https://www.example.com');
91
+ * console.log(isValid); // Output: true
92
+ */
93
+ export function isValidUrl(url) {
94
+ const urlPattern = new RegExp('^(https?:\\/\\/)?' + // Protocol
95
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // Domain name
96
+ '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address
97
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // Port and path
98
+ '(\\?[;&a-z\\d%_.~+=-]*)?' + // Query string
99
+ '(\\#[-a-z\\d_]*)?$', 'i'); // Fragment locator
100
+ return urlPattern.test(url);
101
+ }
102
+ /**
103
+ * Creates a mailto URI and opens it in the user's default email client.
104
+ *
105
+ * This function constructs a mailto URI based on the provided email details and opens it using `window.open`.
106
+ * It supports specifying the recipient, subject, and body of the email.
107
+ *
108
+ * @param param - An object containing the email details:
109
+ * - `to`: The recipient email address.
110
+ * - `body`: Optional. The body content of the email.
111
+ * - `subject`: Optional. The subject of the email.
112
+ *
113
+ * @example
114
+ * // Create a mailto link with recipient, subject, and body
115
+ * createMailtoLink({
116
+ * to: 'recipient@example.com',
117
+ * subject: 'Hello',
118
+ * body: 'This is a sample email message.'
119
+ * });
120
+ */
121
+ export function createMailtoLink({ to, body = '', subject = '' }) {
122
+ const mailtoUri = `mailto:${encodeURIComponent(to)}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
123
+ window.open(mailtoUri, '_self');
124
+ }
125
+ /**
126
+ * Copies the provided text or HTML content to the clipboard.
127
+ *
128
+ * This function handles copying both plain text and rich text (HTML) content.
129
+ * It uses the Clipboard API where available and falls back to older methods for unsupported browsers.
130
+ *
131
+ * @param content - The content to be copied to the clipboard. It can be either a string (plain text) or an HTMLElement (rich text).
132
+ * @returns A promise that resolves to `true` if the copy operation is successful, or `false` otherwise.
133
+ *
134
+ * @example
135
+ * // Copy plain text to clipboard
136
+ * copyToClipboard('Hello, World!').then((success) => {
137
+ * console.log(success ? 'Copied successfully!' : 'Failed to copy.');
138
+ * });
139
+ *
140
+ * @example
141
+ * // Copy rich text (HTML element) to clipboard
142
+ * const element = document.getElementById('myElement');
143
+ * if (element) {
144
+ * copyToClipboard(element).then((success) => {
145
+ * console.log(success ? 'Copied successfully!' : 'Failed to copy.');
146
+ * });
147
+ * }
148
+ */
149
+ export async function copyToClipboard(content) {
150
+ try {
151
+ // If content is a string, attempt to copy it using the Clipboard API
152
+ if (typeof content === 'string') {
153
+ if (navigator.clipboard) {
154
+ await navigator.clipboard.writeText(content);
155
+ return true;
156
+ }
157
+ else {
158
+ // Fallback for older browsers
159
+ const textarea = document.createElement('textarea');
160
+ textarea.value = content;
161
+ textarea.setAttribute('readonly', '');
162
+ textarea.style.position = 'absolute';
163
+ textarea.style.left = '-9999px';
164
+ document.body.appendChild(textarea);
165
+ textarea.select();
166
+ textarea.setSelectionRange(0, 99999); // For mobile devices
167
+ const successful = document.execCommand('copy');
168
+ document.body.removeChild(textarea);
169
+ return successful;
185
170
  }
186
171
  }
187
- // Fallback to filename from URL if Content-Disposition is missing or doesn't contain filename
188
- if (!fileName) {
189
- const urlParts = url.split('/');
190
- fileName = urlParts[urlParts.length - 1] || "";
172
+ // If content is an HTML element, copy its contents as rich text
173
+ if (content instanceof HTMLElement) {
174
+ const range = document.createRange();
175
+ range.selectNodeContents(content);
176
+ const selection = window.getSelection();
177
+ if (!selection)
178
+ return false;
179
+ selection.removeAllRanges();
180
+ selection.addRange(range);
181
+ // Execute the copy command
182
+ const successful = document.execCommand('copy');
183
+ selection.removeAllRanges();
184
+ return successful;
191
185
  }
192
- // Get Content-Type header (MIME type)
193
- const mimeType = res.headers.get('Content-Type') || '';
194
- const buffer = await res.arrayBuffer();
195
- return { buffer, fileName, mimeType };
196
- })
197
- .then(({ buffer, fileName, mimeType }) => {
198
- return new File([buffer], givenFileName || fileName, {
199
- type: givenMimeType || mimeType
200
- });
201
- }));
202
- }
203
- export async function bufferToFile(buffer, filename, mimeType) {
204
- return new File([buffer], filename, {
205
- type: mimeType
206
- });
207
- }
208
- export async function postData(url = '', data = {}) {
209
- // Default options are marked with *
210
- const response = await fetch(url, {
211
- method: 'POST', // *GET, POST, PUT, DELETE, etc.
212
- mode: 'cors', // no-cors, *cors, same-origin
213
- cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
214
- credentials: 'same-origin', // include, *same-origin, omit
215
- headers: {
216
- 'Content-Type': 'application/json'
217
- // 'Content-Type': 'application/x-www-form-urlencoded',
218
- },
219
- redirect: 'follow', // manual, *follow, error
220
- referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
221
- body: JSON.stringify(data) // body data type must match "Content-Type" header
222
- });
223
- return response.json(); // parses JSON response into native JavaScript objects
224
- }
225
- export function fileNameAndExt(filename) {
226
- let arr = (filename || '').split('.');
227
- let ext = arr.pop();
228
- let name = arr.join('.');
229
- return { name, ext };
230
- }
231
- export function isValidateEmail(email) {
232
- const reg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
233
- return reg.test(String(email).toLowerCase());
234
- }
235
- export function isValidURL(str) {
236
- var pattern = new RegExp('^(https?:\\/\\/)?' + // protocol
237
- '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
238
- '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
239
- '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
240
- '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
241
- '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator
242
- return !!pattern.test(str);
243
- }
244
- export function mailto({ to, body = '', subject = '' }) {
245
- var uri = `mailto:${to || ''}?subject=${encodeURIComponent(subject || '')}&body=${encodeURIComponent(body || '')}`;
246
- window.open(uri);
247
- }
248
- export function copyText(str) {
249
- const el = document.createElement('textarea');
250
- el.value = str;
251
- el.setAttribute('readonly', '');
252
- el.style.position = 'absolute';
253
- el.style.left = '-9999px';
254
- document.body.appendChild(el);
255
- el.select();
256
- el.setSelectionRange(0, 99999); /* For mobile devices */
257
- if (navigator.clipboard) {
258
- navigator.clipboard.writeText(str);
259
- }
260
- else {
261
- document.execCommand('copy', false);
186
+ return false; // Unsupported content type
262
187
  }
263
- document.body.removeChild(el);
264
- }
265
- ;
266
- export function copyRichText(node) {
267
- if (BROWSER) {
268
- let r = document.createRange();
269
- r.selectNode(node);
270
- window.getSelection().removeAllRanges();
271
- window.getSelection().addRange(r);
272
- document.execCommand("copy");
273
- window.getSelection().removeAllRanges();
188
+ catch (error) {
189
+ console.error('Failed to copy content to clipboard:', error);
190
+ return false;
274
191
  }
275
192
  }
276
- export function download(data, filename, type) {
277
- const blob = new Blob([data], { type: type || 'application/octet-stream' });
278
- const elem = window.document.createElement('a');
279
- elem.href = window.URL.createObjectURL(blob);
280
- elem.download = filename;
281
- document.body.appendChild(elem);
282
- elem.click();
283
- document.body.removeChild(elem);
284
- }
193
+ /**
194
+ * Formats a string by replacing placeholders `{index}` with corresponding arguments.
195
+ *
196
+ * This function replaces placeholders in the format `{0}`, `{1}`, etc., in the provided string
197
+ * with the corresponding values from the `args` array.
198
+ *
199
+ * @param str - The string containing placeholders.
200
+ * @param args - The values to replace the placeholders with.
201
+ * @returns A formatted string with the placeholders replaced by the corresponding arguments.
202
+ *
203
+ * @example
204
+ * const formatted = formatString('Hello, {0}!', 'World');
205
+ * console.log(formatted); // Output: "Hello, World!"
206
+ */
285
207
  export function formatString(str, ...args) {
286
- var formatted = str;
287
- for (var i = 0; i < args.length; i++) {
288
- var regexp = new RegExp('\\{' + i + '\\}', 'gi');
289
- formatted = formatted.replace(regexp, args[i]);
290
- }
291
- return formatted;
208
+ return args.reduce((formatted, arg, index) => {
209
+ const regexp = new RegExp(`\\{${index}\\}`, 'g');
210
+ return formatted.replace(regexp, arg);
211
+ }, str);
292
212
  }
293
- export function fileSizeString(size) {
294
- var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
295
- return parseInt((size / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
296
- }
297
- export function delay(mills = 0) {
298
- return new Promise((resolve) => {
299
- setTimeout(() => {
300
- resolve();
301
- }, mills);
302
- });
213
+ /**
214
+ * Delays the execution of code for a specified number of milliseconds.
215
+ *
216
+ * This function returns a promise that resolves after the specified delay.
217
+ *
218
+ * @param milliseconds - The number of milliseconds to wait before resolving the promise. Default is 0.
219
+ * @returns A promise that resolves after the specified delay.
220
+ *
221
+ * @example
222
+ * delay(1000).then(() => console.log('1 second later'));
223
+ */
224
+ export function delay(milliseconds = 0) {
225
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
303
226
  }
304
- export function sort({ array, field, desc, isDate }) {
227
+ /**
228
+ * Sorts an array of objects or values based on a specified field or value.
229
+ *
230
+ * This function sorts an array of objects based on a specified field or directly sorts an array of values.
231
+ * It supports both ascending and descending orders and can handle date values.
232
+ *
233
+ * @typeParam T - The type of elements in the array.
234
+ * @param param - An object containing the array to sort, the field to sort by (optional),
235
+ * whether to sort in descending order, and whether to sort as date values.
236
+ * @param param.array - The array of objects or values to sort.
237
+ * @param param.field - Optional. The field of the objects to sort by.
238
+ * @param param.desc - Optional. If true, sorts in descending order. Default is false (ascending).
239
+ * @param param.isDate - Optional. If true, sorts the values as dates.
240
+ * @returns The sorted array.
241
+ *
242
+ * @example
243
+ * const arr = [{ name: 'Alice' }, { name: 'Bob' }];
244
+ * const sortedArr = sort({ array: arr, field: 'name', desc: true });
245
+ * console.log(sortedArr); // Output: [{ name: 'Bob' }, { name: 'Alice' }]
246
+ */
247
+ export function sort({ array, field, desc = false, isDate = false }) {
305
248
  return array.sort((a, b) => {
306
- let valA = typeof a === 'object' && field ? a[field] : a;
307
- let valB = typeof b === 'object' && field ? b[field] : b;
249
+ let valA = field ? a[field] : a;
250
+ let valB = field ? b[field] : b;
251
+ // Convert to Date objects if sorting by date
308
252
  if (isDate) {
309
253
  valA = toDate(valA);
310
254
  valB = toDate(valB);
311
255
  }
312
256
  else {
313
- // Case-insensitive string comparison
257
+ // Convert to lowercase for case-insensitive string comparison
314
258
  if (typeof valA === 'string')
315
259
  valA = valA.toLowerCase();
316
260
  if (typeof valB === 'string')
317
261
  valB = valB.toLowerCase();
318
262
  }
319
- if (valA < valB) {
263
+ // Perform comparison and adjust for descending order if specified
264
+ if (valA < valB)
320
265
  return desc ? 1 : -1;
321
- }
322
- else if (valA > valB) {
266
+ if (valA > valB)
323
267
  return desc ? -1 : 1;
324
- }
325
268
  return 0;
326
269
  });
327
270
  }
271
+ /**
272
+ * Triggers a vibration effect on supported devices.
273
+ *
274
+ * This function uses the Vibration API to trigger a vibration effect. If the Vibration API is not
275
+ * supported or if permissions are not granted, the function will have no effect.
276
+ *
277
+ * @param value - A single number representing the duration of the vibration in milliseconds, or
278
+ * an array of numbers representing vibration patterns.
279
+ *
280
+ * @example
281
+ * // Single vibration for 200 milliseconds
282
+ * vibrate(200);
283
+ *
284
+ * @example
285
+ * // Vibration pattern: 200ms on, 100ms off, 200ms on
286
+ * vibrate([200, 100, 200]);
287
+ */
328
288
  export function vibrate(value = 20) {
329
- if (window?.navigator?.vibrate) {
330
- window.navigator.vibrate(value);
289
+ if (navigator?.vibrate) {
290
+ navigator.vibrate(value);
331
291
  }
332
292
  }
293
+ /**
294
+ * Plays a simple click effect using the vibration API (if supported).
295
+ *
296
+ * This function triggers a short vibration effect to simulate a click or feedback action on devices
297
+ * that support the Vibration API.
298
+ *
299
+ * @example
300
+ * playClickEffect(); // Triggers a short vibration effect.
301
+ */
333
302
  export function playClickEffect() {
334
- vibrate();
303
+ vibrate(20);
335
304
  }
305
+ /**
306
+ * Converts an object into an array of its values, attaching a specified key to each value.
307
+ *
308
+ * This function takes an object and converts it into an array of its values, where each value is
309
+ * augmented with a new property specified by the `key` parameter. The property is set to the key
310
+ * of the original object.
311
+ *
312
+ * @param key - The property name to attach to each value.
313
+ * @param obj - The object to be converted to an array.
314
+ * @returns An array of values with the specified key attached.
315
+ *
316
+ * @example
317
+ * const obj = { a: { name: 'Alice' }, b: { name: 'Bob' } };
318
+ * const array = toArrayByKey('id', obj);
319
+ * console.log(array); // Output: [{ name: 'Alice', id: 'a' }, { name: 'Bob', id: 'b' }]
320
+ */
336
321
  export function toArrayByKey(key, obj = {}) {
337
- return Object.keys(obj).map((k) => {
338
- let data = obj[k];
322
+ return Object.keys(obj)
323
+ .map((k) => {
324
+ const data = obj[k];
339
325
  if (data) {
340
326
  data[key] = k;
341
327
  }
342
328
  return data;
343
- }).filter(o => o) || [];
344
- }
345
- export function convertNumToAlphabates(num) {
346
- let alphabates = 'abcdefghij'.split('');
347
- let numArray = num.toString().split('').map((o) => parseInt(o));
348
- return numArray.map((i) => alphabates[i]).join('');
329
+ })
330
+ .filter((item) => item !== undefined);
349
331
  }
350
- export async function fetchText(url) {
351
- const response = await fetch(url);
352
- let text = await response.text();
353
- // console.log(text)
354
- return text;
332
+ /**
333
+ * Converts a numeric string into its corresponding alphabets (0-9 => a-j).
334
+ *
335
+ * This function maps each digit in the provided number to its corresponding alphabet:
336
+ * - 0 => a, 1 => b, 2 => c, ... , 9 => j.
337
+ *
338
+ * @param num - The number to be converted to a string of alphabets.
339
+ * @returns A string representing the number converted to alphabets.
340
+ *
341
+ * @example
342
+ * const result = convertNumToAlphabets(123); // "bcd"
343
+ * console.log(result); // Output: "bcd"
344
+ */
345
+ export function convertNumToAlphabets(num) {
346
+ const alphabets = 'abcdefghij';
347
+ return num
348
+ .toString()
349
+ .split('')
350
+ .map((digit) => alphabets[parseInt(digit, 10)] || '')
351
+ .join('');
355
352
  }
353
+ /**
354
+ * Converts a number to a currency-formatted string.
355
+ *
356
+ * This function formats a given number as a currency string, using a specified currency symbol
357
+ * (default is '$'). It handles negative values by adding a '-' sign in front of the formatted value.
358
+ *
359
+ * @param value - The numeric value to format as currency.
360
+ * @param symbol - The currency symbol to use. Default is '$'.
361
+ * @returns A formatted string representing the currency value.
362
+ *
363
+ * @example
364
+ * const formattedValue = toCurrency(1234.56, '$');
365
+ * console.log(formattedValue); // Output: "$ 1234.56"
366
+ *
367
+ * @example
368
+ * const formattedNegative = toCurrency(-1234.56, '€');
369
+ * console.log(formattedNegative); // Output: "- € 1234.56"
370
+ */
356
371
  export function toCurrency(value = 0, symbol = '$') {
357
- let currency = Math.abs(value);
358
- let result = '';
359
- if (value < 0) {
360
- result += '- ';
361
- }
362
- if (symbol) {
363
- result += `${symbol} `;
364
- }
365
- result += currency.toFixed(2);
366
- return result;
372
+ const isNegative = value < 0;
373
+ const currencyValue = Math.abs(value).toFixed(2);
374
+ return `${isNegative ? '- ' : ''}${symbol} ${currencyValue}`;
367
375
  }
376
+ /**
377
+ * Converts a length in inches to pixels based on a DPI of 96.
378
+ *
379
+ * This function converts inches to pixels assuming a screen DPI (Dots Per Inch) of 96.
380
+ * It is useful for calculating dimensions in pixels when working with different units of measurement.
381
+ *
382
+ * @param inches - The length in inches to be converted to pixels.
383
+ * @returns The length in pixels corresponding to the provided inches.
384
+ *
385
+ * @throws An error if the input is not a valid number or is negative.
386
+ *
387
+ * @example
388
+ * const pixels = inchToPixel(1); // 1 inch to pixels
389
+ * console.log(pixels); // Output: 96
390
+ */
368
391
  export function inchToPixel(inches) {
369
- return inches * 96; // DPI
392
+ if (typeof inches !== 'number' || isNaN(inches) || inches < 0) {
393
+ throw new Error('Invalid input: Inches must be a non-negative number.');
394
+ }
395
+ const DPI = 96; // Default DPI for screen resolution
396
+ return inches * DPI;
370
397
  }
398
+ /**
399
+ * Converts a length in pixels to inches based on a DPI of 96.
400
+ *
401
+ * This function converts pixels to inches assuming a screen DPI (Dots Per Inch) of 96.
402
+ * It is useful for converting pixel measurements to physical dimensions.
403
+ *
404
+ * @param pixels - The length in pixels to be converted to inches.
405
+ * @returns The length in inches corresponding to the provided pixels.
406
+ *
407
+ * @throws An error if the input is not a valid number or is negative.
408
+ *
409
+ * @example
410
+ * const inches = pixelToInch(96); // 96 pixels to inches
411
+ * console.log(inches); // Output: 1
412
+ */
371
413
  export function pixelToInch(pixels) {
372
- return pixels / 96; // DPI
373
- }
374
- export function isValidHexColor(hex) {
375
- const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
376
- let res = hexRegex.test(hex);
377
- return res;
378
- }
379
- export function colorToHex(color) {
380
- // Create a temporary div element to use its computed style
381
- const tempDiv = document.createElement("div");
382
- tempDiv.style.color = color;
383
- document.body.appendChild(tempDiv);
384
- // Get the computed color from the div element
385
- const computedColor = window.getComputedStyle(tempDiv).color;
386
- document.body.removeChild(tempDiv);
387
- // Convert the computed color to RGB values
388
- const rgb = computedColor.match(/\d+/g).map(Number);
389
- // Convert RGB values to a 6-character hex color
390
- const hexColor = rgbToHex(rgb[0], rgb[1], rgb[2]);
391
- return hexColor;
392
- }
393
- export function rgbToHex(r, g, b) {
394
- return ("#" +
395
- [r, g, b]
396
- .map((x) => x.toString(16).padStart(2, "0")) // Convert to hex and ensure two characters
397
- .join("")
398
- .toUpperCase());
414
+ if (typeof pixels !== 'number' || isNaN(pixels) || pixels < 0) {
415
+ throw new Error('Invalid input: Pixels must be a non-negative number.');
416
+ }
417
+ const DPI = 96; // Default DPI for screen resolution
418
+ return pixels / DPI;
399
419
  }