@herowcode/utils 1.0.2 → 1.1.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.
Files changed (82) hide show
  1. package/README.md +236 -81
  2. package/dist/files/compress-image.d.ts +10 -0
  3. package/dist/files/compress-image.d.ts.map +1 -0
  4. package/dist/files/compress-image.esm.js +57 -0
  5. package/dist/files/compress-image.js +57 -0
  6. package/dist/files/compress-image.js.map +1 -0
  7. package/dist/files/download-url.d.ts +2 -0
  8. package/dist/files/download-url.d.ts.map +1 -0
  9. package/dist/files/download-url.esm.js +24 -0
  10. package/dist/files/download-url.js +24 -0
  11. package/dist/files/download-url.js.map +1 -0
  12. package/dist/files/format-bytes.d.ts +2 -0
  13. package/dist/files/format-bytes.d.ts.map +1 -0
  14. package/dist/files/format-bytes.esm.js +13 -0
  15. package/dist/files/format-bytes.js +13 -0
  16. package/dist/files/format-bytes.js.map +1 -0
  17. package/dist/files/index.d.ts +4 -0
  18. package/dist/files/index.d.ts.map +1 -0
  19. package/dist/files/index.esm.js +3 -0
  20. package/dist/files/index.js +3 -0
  21. package/dist/files/index.js.map +1 -0
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.esm.js +6 -10
  25. package/dist/index.js +6 -10
  26. package/dist/index.js.map +1 -1
  27. package/dist/string/format-hms-to-seconds.d.ts +2 -0
  28. package/dist/string/format-hms-to-seconds.d.ts.map +1 -0
  29. package/dist/string/format-hms-to-seconds.esm.js +25 -0
  30. package/dist/string/format-hms-to-seconds.js +25 -0
  31. package/dist/string/format-hms-to-seconds.js.map +1 -0
  32. package/dist/string/format-seconds-to-fragment.d.ts +3 -0
  33. package/dist/string/format-seconds-to-fragment.d.ts.map +1 -0
  34. package/dist/string/format-seconds-to-fragment.esm.js +15 -0
  35. package/dist/string/format-seconds-to-fragment.js +15 -0
  36. package/dist/string/format-seconds-to-fragment.js.map +1 -0
  37. package/dist/string/format-seconds-to-hms.d.ts +2 -0
  38. package/dist/string/format-seconds-to-hms.d.ts.map +1 -0
  39. package/dist/string/format-seconds-to-hms.esm.js +13 -0
  40. package/dist/string/format-seconds-to-hms.js +13 -0
  41. package/dist/string/format-seconds-to-hms.js.map +1 -0
  42. package/dist/string/format-string-to-time.d.ts +2 -0
  43. package/dist/string/format-string-to-time.d.ts.map +1 -0
  44. package/dist/string/format-string-to-time.esm.js +10 -0
  45. package/dist/string/format-string-to-time.js +10 -0
  46. package/dist/string/format-string-to-time.js.map +1 -0
  47. package/dist/string/index.d.ts +4 -0
  48. package/dist/string/index.d.ts.map +1 -1
  49. package/dist/string/index.esm.js +4 -0
  50. package/dist/string/index.js +4 -0
  51. package/dist/string/index.js.map +1 -1
  52. package/dist/youtube/extract-youtube-video-id.d.ts +2 -0
  53. package/dist/youtube/extract-youtube-video-id.d.ts.map +1 -0
  54. package/dist/youtube/extract-youtube-video-id.esm.js +26 -0
  55. package/dist/youtube/extract-youtube-video-id.js +26 -0
  56. package/dist/youtube/extract-youtube-video-id.js.map +1 -0
  57. package/dist/youtube/generate-youtube-url.d.ts +20 -0
  58. package/dist/youtube/generate-youtube-url.d.ts.map +1 -0
  59. package/dist/youtube/generate-youtube-url.esm.js +81 -0
  60. package/dist/youtube/generate-youtube-url.js +81 -0
  61. package/dist/youtube/generate-youtube-url.js.map +1 -0
  62. package/dist/youtube/index.d.ts +5 -0
  63. package/dist/youtube/index.d.ts.map +1 -0
  64. package/dist/youtube/index.esm.js +4 -0
  65. package/dist/youtube/index.js +4 -0
  66. package/dist/youtube/index.js.map +1 -0
  67. package/dist/youtube/use-get-video-duration.d.ts +7 -0
  68. package/dist/youtube/use-get-video-duration.d.ts.map +1 -0
  69. package/dist/youtube/use-get-video-duration.esm.js +150 -0
  70. package/dist/youtube/use-get-video-duration.js +150 -0
  71. package/dist/youtube/use-get-video-duration.js.map +1 -0
  72. package/dist/youtube/validate-youtube-link.d.ts +2 -0
  73. package/dist/youtube/validate-youtube-link.d.ts.map +1 -0
  74. package/dist/youtube/validate-youtube-link.esm.js +40 -0
  75. package/dist/youtube/validate-youtube-link.js +40 -0
  76. package/dist/youtube/validate-youtube-link.js.map +1 -0
  77. package/package.json +33 -17
  78. package/dist/number.d.ts +0 -8
  79. package/dist/number.d.ts.map +0 -1
  80. package/dist/number.esm.js +0 -15
  81. package/dist/number.js +0 -15
  82. package/dist/number.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @herowcode/utils
2
2
 
3
- A lightweight collection of utility functions for everyday JavaScript/TypeScript development. Built with dayjs for powerful date manipulation.
3
+ A lightweight collection of utility functions for everyday JavaScript/TypeScript development. Built with dayjs for powerful date manipulation and React hooks for YouTube integration.
4
4
 
5
5
  ## Features
6
6
 
@@ -10,6 +10,7 @@ A lightweight collection of utility functions for everyday JavaScript/TypeScript
10
10
  - 📱 **Universal** - Works in Node.js and browsers
11
11
  - 🎯 **Tree-shakable** - Only import what you need
12
12
  - 📂 **Scoped exports** - Import from specific modules
13
+ - 🎥 **YouTube utilities** - Extract video IDs, generate URLs, and get video durations
13
14
 
14
15
  ## Installation
15
16
 
@@ -23,7 +24,7 @@ yarn add @herowcode/utils
23
24
 
24
25
  ### Import everything:
25
26
  ```typescript
26
- import { formatDate, capitalize, debounce } from '@herowcode/utils';
27
+ import { formatDate, capitalize, debounce, extractYouTubeId } from '@herowcode/utils';
27
28
  ```
28
29
 
29
30
  ### Import by scope:
@@ -32,6 +33,7 @@ import { formatDate, addDays } from '@herowcode/utils/date';
32
33
  import { capitalize, camelCase } from '@herowcode/utils/string';
33
34
  import { randomInt } from '@herowcode/utils/number';
34
35
  import { debounce, throttle } from '@herowcode/utils/function';
36
+ import { extractYouTubeId, generateYoutubeURL } from '@herowcode/utils/youtube';
35
37
  ```
36
38
 
37
39
  ### Examples:
@@ -47,137 +49,297 @@ console.log(kebabCase('helloWorld')); // "hello-world"
47
49
 
48
50
  // Function utilities
49
51
  const debouncedFn = debounce(() => console.log('Called!'), 300);
52
+
53
+ // YouTube utilities
54
+ const videoId = extractYouTubeId('https://youtu.be/dQw4w9WgXcQ'); // "dQw4w9WgXcQ"
55
+ const embedUrl = generateYoutubeURL({
56
+ videoURL: 'https://youtu.be/abc123',
57
+ embed: true,
58
+ autoplay: true
59
+ }); // "https://www.youtube.com/embed/abc123?autoplay=1"
50
60
  ```
51
61
 
52
62
  ## API Reference
53
63
 
64
+ ### Array Utilities
65
+
66
+ #### `shuffle<T>(array: T[]): T[]`
67
+ Returns a new array with the elements shuffled in random order.
68
+
69
+ ```typescript
70
+ shuffle([1, 2, 3, 4]); // e.g., [3, 1, 4, 2]
71
+ ```
72
+
73
+ #### `unique<T>(array: T[]): T[]`
74
+ Removes duplicate values from an array, preserving the first occurrence.
75
+
76
+ ```typescript
77
+ unique([1, 2, 2, 3, 1]); // [1, 2, 3]
78
+ ```
79
+
54
80
  ### Date Utilities
55
81
 
56
- #### `formatDate(date: Date, format: string): string`
82
+ #### `formatDate(date: Date | string | number, locale?: string, opts?: Intl.DateTimeFormatOptions): string`
83
+ Formats a date using the specified locale and options.
57
84
 
58
- Formats a date according to the specified format.
85
+ ```typescript
86
+ formatDate(new Date('2023-12-25'), 'en-US'); // "December 25, 2023"
87
+ ```
88
+
89
+ #### `fixTimezoneOffset(utcDate: Date | string): Dayjs`
90
+ Adjusts a UTC date string or Date object for the local timezone offset.
91
+
92
+ ```typescript
93
+ fixTimezoneOffset('2025-09-08T12:00:00Z');
94
+ ```
59
95
 
60
- **Supported format tokens:**
61
- - `YYYY` - 4-digit year
62
- - `YY` - 2-digit year
63
- - `MM` - 2-digit month (01-12)
64
- - `DD` - 2-digit day (01-31)
65
- - `HH` - 2-digit hours (00-23)
66
- - `mm` - 2-digit minutes (00-59)
67
- - `ss` - 2-digit seconds (00-59)
96
+ #### `getCurrentDateInUTC(): Dayjs`
97
+ Returns the current date/time as a Dayjs object in UTC.
68
98
 
69
99
  ```typescript
70
- formatDate(new Date('2023-12-25'), 'YYYY-MM-DD'); // "2023-12-25"
71
- formatDate(new Date('2023-12-25'), 'DD/MM/YYYY'); // "25/12/2023"
72
- formatDate(new Date('2023-12-25T10:30:45'), 'DD/MM/YYYY HH:mm:ss'); // "25/12/2023 10:30:45"
100
+ getCurrentDateInUTC();
73
101
  ```
74
102
 
75
- #### `addDays(date: Date, amount: number): Date`
103
+ #### `getDateInUTC(date: Date): Dayjs`
104
+ Converts a Date to a Dayjs object in UTC.
76
105
 
77
- Adds a specified number of days to a date. Returns a new Date object.
106
+ ```typescript
107
+ getDateInUTC(new Date());
108
+ ```
109
+
110
+ #### `parseTimeSpent(initialDate: string | Date, finalDate: string | Date, locale?: string): string`
111
+ Returns a human-readable string describing the time difference between two dates, localized.
78
112
 
79
113
  ```typescript
80
- const date = new Date('2023-12-25');
81
- addDays(date, 5); // 2023-12-30
82
- addDays(date, -5); // 2023-12-20
114
+ parseTimeSpent('2020-01-01', '2022-04-16', 'en-US'); // "2 years, 3 months, and 15 days"
83
115
  ```
84
116
 
85
- #### `diffInDays(date1: Date, date2: Date): number`
117
+ ### Files Utilities
86
118
 
87
- Calculates the difference in days between two dates.
119
+ #### `compressImage({ file, maxWidth, maxHeight, quality, allowedFileTypes }): Promise<File>`
120
+ Compresses an image file to WebP format, optionally resizing and restricting file types.
88
121
 
89
122
  ```typescript
90
- const date1 = new Date('2023-12-30');
91
- const date2 = new Date('2023-12-25');
92
- diffInDays(date1, date2); // 5
93
- diffInDays(date2, date1); // -5
123
+ await compressImage({ file, maxWidth: 800, maxHeight: 600, quality: 0.8 });
94
124
  ```
95
125
 
96
- #### `isBefore(date1: Date, date2: Date): boolean`
126
+ #### `downloadUrl(url: string): Promise<boolean>`
127
+ Downloads a file from a URL in the browser, returning true if successful.
97
128
 
98
- Checks if the first date is before the second date.
129
+ ```typescript
130
+ await downloadUrl('https://example.com/file.pdf');
131
+ ```
132
+
133
+ #### `formatBytes(bytes: number): string`
134
+ Formats a byte count as a human-readable string (e.g., "1.23 MB").
99
135
 
100
136
  ```typescript
101
- const date1 = new Date('2023-12-20');
102
- const date2 = new Date('2023-12-25');
103
- isBefore(date1, date2); // true
104
- isBefore(date2, date1); // false
137
+ formatBytes(1234567); // "1.18 MB"
105
138
  ```
106
139
 
107
- #### `isAfter(date1: Date, date2: Date): boolean`
140
+ ### Function Utilities
141
+
142
+ #### `debounce<T>(fn: T, delay: number): (...args: Parameters<T>) => void`
143
+ Creates a debounced function that delays invoking `fn` until after `delay` ms have elapsed since the last call.
144
+
145
+ ```typescript
146
+ const debounced = debounce(() => { /* ... */ }, 300);
147
+ ```
108
148
 
109
- Checks if the first date is after the second date.
149
+ #### `throttle<T>(fn: T, delay: number): (...args: Parameters<T>) => void`
150
+ Creates a throttled function that only invokes `fn` at most once per `delay` ms.
110
151
 
111
152
  ```typescript
112
- const date1 = new Date('2023-12-30');
113
- const date2 = new Date('2023-12-25');
114
- isAfter(date1, date2); // true
115
- isAfter(date2, date1); // false
153
+ const throttled = throttle(() => { /* ... */ }, 100);
154
+ ```
155
+
156
+ #### `tryCatch<T, E = Error, D = null>(fn: Promise<T> | (() => Promise<T> | T), defaultData?: D): Promise<{ data: T | D; error: E | null }>`
157
+ Executes a function or promise and returns an object with `data` or `error`.
158
+
159
+ ```typescript
160
+ const result = await tryCatch(() => fetchData());
161
+ if (result.error) { /* handle error */ }
116
162
  ```
117
163
 
118
164
  ### String Utilities
119
165
 
166
+ #### `camelCase(str: string): string`
167
+ Converts a string to camelCase.
168
+
169
+ ```typescript
170
+ camelCase('hello world'); // "helloWorld"
171
+ ```
172
+
120
173
  #### `capitalize(str: string): string`
174
+ Capitalizes the first letter and lowercases the rest.
121
175
 
122
- Capitalizes the first letter of a string and converts the rest to lowercase.
176
+ ```typescript
177
+ capitalize('hELLO'); // "Hello"
178
+ ```
179
+
180
+ #### `formatHMSToSeconds(val?: number | string): number | null`
181
+ Converts HMS time format or numeric strings to seconds. Supports formats like "90", "01:30", "1:02:03".
123
182
 
124
183
  ```typescript
125
- capitalize('hello world'); // "Hello world"
126
- capitalize('HELLO WORLD'); // "Hello world"
127
- capitalize('hELLo WoRLd'); // "Hello world"
184
+ formatHMSToSeconds("1:30"); // 90
185
+ formatHMSToSeconds("1:02:03"); // 3723
186
+ formatHMSToSeconds(120); // 120
128
187
  ```
129
188
 
130
- #### `camelCase(str: string): string`
189
+ #### `formatSecondsToFragment(secs: number): string`
190
+ Converts seconds to YouTube-style fragment format (e.g., "1h2m3s").
191
+
192
+ ```typescript
193
+ formatSecondsToFragment(3723); // "1h2m3s"
194
+ formatSecondsToFragment(90); // "1m30s"
195
+ formatSecondsToFragment(42); // "42s"
196
+ ```
131
197
 
132
- Converts a string to camelCase by removing special characters and capitalizing words.
198
+ #### `formatSecondsToHMS(totalSeconds: number): string`
199
+ Formats a number of seconds into an HH:MM:SS string, rounding and clamping negatives to zero.
133
200
 
134
201
  ```typescript
135
- camelCase('hello world'); // "helloWorld"
136
- camelCase('hello-world'); // "helloWorld"
137
- camelCase('hello_world_test'); // "helloWorldTest"
138
- camelCase('The Quick Brown Fox'); // "theQuickBrownFox"
202
+ formatSecondsToHMS(3661); // "01:01:01"
203
+ formatSecondsToHMS(5); // "00:05"
139
204
  ```
140
205
 
141
- ### Number Utilities
206
+ #### `formatStringToTime(str: string): string`
207
+ Parses a numeric time string (or a string containing digits) into MM:SS or HH:MM:SS format. Non-digits are removed before formatting. Short inputs are zero-padded.
142
208
 
143
- #### `randomInt(min: number, max: number): number`
209
+ ```typescript
210
+ formatStringToTime('123'); // "01:23"
211
+ formatStringToTime('12345'); // "01:23:45"
212
+ formatStringToTime(' 12:34 '); // "12:34"
213
+ ```
144
214
 
145
- Generates a random integer between min and max (inclusive).
215
+ #### `kebabCase(str: string): string`
216
+ Converts a string to kebab-case.
146
217
 
147
218
  ```typescript
148
- randomInt(1, 10); // Random integer between 1 and 10
149
- randomInt(0, 100); // Random integer between 0 and 100
150
- randomInt(-5, 5); // Random integer between -5 and 5
219
+ kebabCase('Hello World'); // "hello-world"
151
220
  ```
152
221
 
153
- ### Function Utilities
222
+ #### `removeHtmlTags(input: string): string`
223
+ Removes all HTML tags from a string.
224
+
225
+ ```typescript
226
+ removeHtmlTags('<p>Hello</p>'); // "Hello"
227
+ ```
228
+
229
+ #### `slugify(text: string): string`
230
+ Converts a string to a URL-friendly slug.
231
+
232
+ ```typescript
233
+ slugify('Hello World!'); // "hello-world"
234
+ ```
235
+
236
+ #### `snakeCase(str: string): string`
237
+ Converts a string to snake_case.
238
+
239
+ ```typescript
240
+ snakeCase('Hello World'); // "hello_world"
241
+ ```
154
242
 
155
- #### `debounce<T>(fn: T, delay: number): T`
243
+ #### `toSentenceCase(str: string): string`
244
+ Converts a string to sentence case.
156
245
 
157
- Creates a debounced function that delays invoking `fn` until after `delay` milliseconds have elapsed since the last time it was invoked.
246
+ ```typescript
247
+ toSentenceCase('helloWorld'); // "Hello world"
248
+ ```
249
+
250
+ #### `truncate(str: string, length: number, suffix = "..."): string`
251
+ Truncates a string to a specified length, appending a suffix if truncated.
158
252
 
159
253
  ```typescript
160
- const debouncedSearch = debounce((query: string) => {
161
- console.log('Searching for:', query);
162
- }, 300);
254
+ truncate('Hello world', 5); // "He..."
255
+ ```
163
256
 
164
- // Will only execute once after 300ms of no new calls
165
- debouncedSearch('a');
166
- debouncedSearch('ab');
167
- debouncedSearch('abc'); // Only this will execute
257
+ ### YouTube Utilities
258
+
259
+ #### `extractYouTubeId(urlString: string | null): string | null`
260
+ Extracts the video ID from various YouTube URL formats.
261
+
262
+ ```typescript
263
+ extractYouTubeId('https://youtu.be/dQw4w9WgXcQ'); // "dQw4w9WgXcQ"
264
+ extractYouTubeId('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); // "dQw4w9WgXcQ"
265
+ extractYouTubeId('https://www.youtube.com/embed/dQw4w9WgXcQ'); // "dQw4w9WgXcQ"
266
+ extractYouTubeId('invalid-url'); // null
168
267
  ```
169
268
 
170
- #### `throttle<T>(fn: T, delay: number): T`
269
+ #### `generateYoutubeURL(options: TCreateYoutubeLinkOptions): string | null`
270
+ Generates YouTube URLs with various options for watch, embed, or short formats.
171
271
 
172
- Creates a throttled function that only invokes `fn` at most once per every `delay` milliseconds.
272
+ ```typescript
273
+ // Basic watch URL
274
+ generateYoutubeURL({ videoURL: 'https://youtu.be/abc123' });
275
+ // "https://www.youtube.com/watch?v=abc123"
276
+
277
+ // Embed URL with autoplay
278
+ generateYoutubeURL({
279
+ videoURL: 'https://youtu.be/abc123',
280
+ embed: true,
281
+ autoplay: true
282
+ });
283
+ // "https://www.youtube.com/embed/abc123?autoplay=1"
284
+
285
+ // Short URL with timestamp
286
+ generateYoutubeURL({
287
+ videoURL: 'https://youtu.be/abc123',
288
+ short: true,
289
+ start: "1:30"
290
+ });
291
+ // "https://youtu.be/abc123?t=90"
292
+
293
+ // URL with fragment timestamp
294
+ generateYoutubeURL({
295
+ videoURL: 'https://youtu.be/abc123',
296
+ start: "1:30",
297
+ useFragment: true
298
+ });
299
+ // "https://www.youtube.com/watch?v=abc123#t=1m30s"
300
+ ```
301
+
302
+ **Options:**
303
+ - `videoURL` (required): YouTube URL to process
304
+ - `start`/`end`: Start/end times as seconds (number) or HMS strings ("90", "01:30", "1:02:03")
305
+ - `embed`: Generate embed URL format
306
+ - `short`: Generate youtu.be short URL format
307
+ - `useFragment`: Use #t=1m2s style fragment for timestamps
308
+ - `autoplay`, `controls`, `rel`, `loop`, `mute`, `modestbranding`: Player options
309
+ - `origin`, `playlist`: Additional parameters
310
+ - `params`: Custom query parameters
311
+
312
+ #### `useGetYoutubeVideoDuration(): (videoUrl: string) => Promise<string | null>`
313
+ React hook that returns a function to get YouTube video duration using the YouTube IFrame API.
173
314
 
174
315
  ```typescript
175
- const throttledScroll = throttle(() => {
176
- console.log('Scroll event handled');
177
- }, 100);
316
+ import { useGetYoutubeVideoDuration } from '@herowcode/utils/youtube';
317
+
318
+ function VideoComponent() {
319
+ const getVideoDuration = useGetYoutubeVideoDuration();
320
+
321
+ const handleGetDuration = async () => {
322
+ const duration = await getVideoDuration('https://youtu.be/dQw4w9WgXcQ');
323
+ console.log(duration); // "03:32" or null if failed
324
+ };
325
+
326
+ return <button onClick={handleGetDuration}>Get Duration</button>;
327
+ }
328
+ ```
329
+
330
+ **Features:**
331
+ - Automatically loads YouTube IFrame API if not present
332
+ - Creates offscreen iframe for duration detection
333
+ - Handles retry logic for videos that don't immediately report duration
334
+ - 10-second timeout with automatic cleanup
335
+ - Returns formatted duration string (HH:MM:SS) or null on failure
336
+
337
+ #### `validateYoutubeLink(videoUrl: string): Promise<boolean>`
338
+ Checks whether a YouTube video exists by probing thumbnails and falling back to the oEmbed endpoint. Returns `true` for found/public videos and `false` otherwise.
178
339
 
179
- // Will execute immediately, then at most once every 100ms
180
- window.addEventListener('scroll', throttledScroll);
340
+ ```typescript
341
+ const ok = await validateYoutubeLink('https://youtu.be/dQw4w9WgXcQ');
342
+ // true | false
181
343
  ```
182
344
 
183
345
  ## Browser Support
@@ -187,6 +349,8 @@ This library supports all modern browsers and Node.js environments. It uses ES20
187
349
  - Node.js 10+
188
350
  - Modern browsers (Chrome 63+, Firefox 58+, Safari 12+, Edge 79+)
189
351
 
352
+ The YouTube utilities require a browser environment with DOM support.
353
+
190
354
  ## Development
191
355
 
192
356
  ```bash
@@ -212,13 +376,4 @@ MIT © [HerowCode](https://github.com/herowcode)
212
376
 
213
377
  ## Contributing
214
378
 
215
- Contributions are welcome! Please feel free to submit a Pull Request.
216
-
217
- ## Changelog
218
-
219
- ### 1.0.0
220
- - Initial release
221
- - Date utilities: `formatDate`, `addDays`, `diffInDays`, `isBefore`, `isAfter`
222
- - String utilities: `capitalize`, `camelCase`
223
- - Number utilities: `randomInt`
224
- - Function utilities: `debounce`, `throttle`
379
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,10 @@
1
+ interface ICompressImageParams {
2
+ file: File;
3
+ maxWidth?: number;
4
+ maxHeight?: number;
5
+ quality?: number;
6
+ allowedFileTypes?: string[];
7
+ }
8
+ export declare function compressImage({ file, maxWidth, maxHeight, quality, allowedFileTypes, }: ICompressImageParams): Promise<File>;
9
+ export {};
10
+ //# sourceMappingURL=compress-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress-image.d.ts","sourceRoot":"","sources":["../../src/files/compress-image.ts"],"names":[],"mappings":"AAAA,UAAU,oBAAoB;IAC5B,IAAI,EAAE,IAAI,CAAA;IACV,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B;AAYD,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAmC,EACnC,SAAoC,EACpC,OAAW,EACX,gBAAyE,GAC1E,EAAE,oBAAoB,iBAiEtB"}
@@ -0,0 +1,57 @@
1
+ function convertToWebp(filename) {
2
+ const lastDotIndex = filename.lastIndexOf(".");
3
+ if (lastDotIndex === -1) {
4
+ return `${filename}.webp`;
5
+ }
6
+ return `${filename.substring(0, lastDotIndex)}.webp`;
7
+ }
8
+ export function compressImage({ file, maxWidth = Number.POSITIVE_INFINITY, maxHeight = Number.POSITIVE_INFINITY, quality = 1, allowedFileTypes = ["image/jpg", "image/jpeg", "image/png", "image/webp"], }) {
9
+ if (!allowedFileTypes.includes(file.type)) {
10
+ throw new Error("Image format not supported");
11
+ }
12
+ return new Promise((resolve, reject) => {
13
+ const reader = new FileReader();
14
+ reader.onload = (event) => {
15
+ var _a;
16
+ const compressed = new Image();
17
+ compressed.onload = () => {
18
+ const canvas = document.createElement("canvas");
19
+ let width = compressed.width;
20
+ let height = compressed.height;
21
+ if (width > height) {
22
+ if (width > maxWidth) {
23
+ height *= maxWidth / width;
24
+ width = maxWidth;
25
+ }
26
+ }
27
+ else {
28
+ if (height > maxHeight) {
29
+ width *= maxHeight / height;
30
+ height = maxHeight;
31
+ }
32
+ }
33
+ canvas.width = width;
34
+ canvas.height = height;
35
+ const context = canvas.getContext("2d");
36
+ if (!context) {
37
+ reject(new Error("Failed to get canvas context"));
38
+ return;
39
+ }
40
+ context.drawImage(compressed, 0, 0, width, height);
41
+ canvas.toBlob((blob) => {
42
+ if (!blob) {
43
+ reject(new Error("Failed to compress image."));
44
+ return;
45
+ }
46
+ const compressedFile = new File([blob], convertToWebp(file.name), {
47
+ type: "image/webp",
48
+ lastModified: Date.now(),
49
+ });
50
+ resolve(compressedFile);
51
+ }, "image/webp", quality);
52
+ };
53
+ compressed.src = (_a = event.target) === null || _a === void 0 ? void 0 : _a.result;
54
+ };
55
+ reader.readAsDataURL(file);
56
+ });
57
+ }
@@ -0,0 +1,57 @@
1
+ function convertToWebp(filename) {
2
+ const lastDotIndex = filename.lastIndexOf(".");
3
+ if (lastDotIndex === -1) {
4
+ return `${filename}.webp`;
5
+ }
6
+ return `${filename.substring(0, lastDotIndex)}.webp`;
7
+ }
8
+ export function compressImage({ file, maxWidth = Number.POSITIVE_INFINITY, maxHeight = Number.POSITIVE_INFINITY, quality = 1, allowedFileTypes = ["image/jpg", "image/jpeg", "image/png", "image/webp"], }) {
9
+ if (!allowedFileTypes.includes(file.type)) {
10
+ throw new Error("Image format not supported");
11
+ }
12
+ return new Promise((resolve, reject) => {
13
+ const reader = new FileReader();
14
+ reader.onload = (event) => {
15
+ var _a;
16
+ const compressed = new Image();
17
+ compressed.onload = () => {
18
+ const canvas = document.createElement("canvas");
19
+ let width = compressed.width;
20
+ let height = compressed.height;
21
+ if (width > height) {
22
+ if (width > maxWidth) {
23
+ height *= maxWidth / width;
24
+ width = maxWidth;
25
+ }
26
+ }
27
+ else {
28
+ if (height > maxHeight) {
29
+ width *= maxHeight / height;
30
+ height = maxHeight;
31
+ }
32
+ }
33
+ canvas.width = width;
34
+ canvas.height = height;
35
+ const context = canvas.getContext("2d");
36
+ if (!context) {
37
+ reject(new Error("Failed to get canvas context"));
38
+ return;
39
+ }
40
+ context.drawImage(compressed, 0, 0, width, height);
41
+ canvas.toBlob((blob) => {
42
+ if (!blob) {
43
+ reject(new Error("Failed to compress image."));
44
+ return;
45
+ }
46
+ const compressedFile = new File([blob], convertToWebp(file.name), {
47
+ type: "image/webp",
48
+ lastModified: Date.now(),
49
+ });
50
+ resolve(compressedFile);
51
+ }, "image/webp", quality);
52
+ };
53
+ compressed.src = (_a = event.target) === null || _a === void 0 ? void 0 : _a.result;
54
+ };
55
+ reader.readAsDataURL(file);
56
+ });
57
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress-image.js","sourceRoot":"","sources":["../../src/files/compress-image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const downloadUrl: (url: string) => Promise<boolean>;
2
+ //# sourceMappingURL=download-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-url.d.ts","sourceRoot":"","sources":["../../src/files/download-url.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,OAAO,CAyB9D,CAAA"}
@@ -0,0 +1,24 @@
1
+ export const downloadUrl = async (url) => {
2
+ try {
3
+ const urlObj = new URL(url);
4
+ const pathname = urlObj.pathname;
5
+ const segments = pathname.split("/").filter((segment) => segment.length > 0);
6
+ const filename = segments.length > 0 ? segments[segments.length - 1] : null;
7
+ if (!filename || !filename.includes(".")) {
8
+ throw new Error("URL does not contain a valid filename");
9
+ }
10
+ const response = await fetch(url, { mode: "cors" });
11
+ const blob = await response.blob();
12
+ const link = document.createElement("a");
13
+ link.href = window.URL.createObjectURL(blob);
14
+ link.download = filename;
15
+ document.body.appendChild(link);
16
+ link.click();
17
+ document.body.removeChild(link);
18
+ return true;
19
+ }
20
+ catch (error) {
21
+ console.error("Error downloading the file", error);
22
+ return false;
23
+ }
24
+ };
@@ -0,0 +1,24 @@
1
+ export const downloadUrl = async (url) => {
2
+ try {
3
+ const urlObj = new URL(url);
4
+ const pathname = urlObj.pathname;
5
+ const segments = pathname.split("/").filter((segment) => segment.length > 0);
6
+ const filename = segments.length > 0 ? segments[segments.length - 1] : null;
7
+ if (!filename || !filename.includes(".")) {
8
+ throw new Error("URL does not contain a valid filename");
9
+ }
10
+ const response = await fetch(url, { mode: "cors" });
11
+ const blob = await response.blob();
12
+ const link = document.createElement("a");
13
+ link.href = window.URL.createObjectURL(blob);
14
+ link.download = filename;
15
+ document.body.appendChild(link);
16
+ link.click();
17
+ document.body.removeChild(link);
18
+ return true;
19
+ }
20
+ catch (error) {
21
+ console.error("Error downloading the file", error);
22
+ return false;
23
+ }
24
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-url.js","sourceRoot":"","sources":["../../src/files/download-url.ts"],"names":[],"mappings":";;;AAAO,MAAM,WAAW,GAAG,KAAK,EAAE,GAAW,EAAoB,EAAE;IACjE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAA;QAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAC5E,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAE3E,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC1D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QACnD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAElC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;QACxC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;QAC5C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAA;QAClD,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAzBY,QAAA,WAAW,eAyBvB"}
@@ -0,0 +1,2 @@
1
+ export declare function formatBytes(bytes: number): string;
2
+ //# sourceMappingURL=format-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-bytes.d.ts","sourceRoot":"","sources":["../../src/files/format-bytes.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAejD"}
@@ -0,0 +1,13 @@
1
+ export function formatBytes(bytes) {
2
+ if (bytes < 0) {
3
+ throw new Error("Size in bytes cannot be negative");
4
+ }
5
+ const units = ["B", "KB", "MB", "GB", "TB", "PB"];
6
+ let size = bytes;
7
+ let index = 0;
8
+ while (size >= 1024 && index < units.length - 1) {
9
+ size /= 1024;
10
+ index++;
11
+ }
12
+ return `${size.toFixed(2)} ${units[index]}`;
13
+ }
@@ -0,0 +1,13 @@
1
+ export function formatBytes(bytes) {
2
+ if (bytes < 0) {
3
+ throw new Error("Size in bytes cannot be negative");
4
+ }
5
+ const units = ["B", "KB", "MB", "GB", "TB", "PB"];
6
+ let size = bytes;
7
+ let index = 0;
8
+ while (size >= 1024 && index < units.length - 1) {
9
+ size /= 1024;
10
+ index++;
11
+ }
12
+ return `${size.toFixed(2)} ${units[index]}`;
13
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-bytes.js","sourceRoot":"","sources":["../../src/files/format-bytes.ts"],"names":[],"mappings":";;AAAA,kCAeC;AAfD,SAAgB,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACjD,IAAI,IAAI,GAAG,KAAK,CAAA;IAChB,IAAI,KAAK,GAAG,CAAC,CAAA;IAEb,OAAO,IAAI,IAAI,IAAI,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,IAAI,IAAI,IAAI,CAAA;QACZ,KAAK,EAAE,CAAA;IACT,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAA;AAC7C,CAAC"}