@myusufazmi/ultimate-tools 1.1.0 → 1.2.0
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/index.cjs.js +531 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.js +504 -0
- package/dist/index.js.map +1 -0
- package/dist/index.min.js +2 -0
- package/dist/index.min.js.map +1 -0
- package/package.json +13 -5
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOM Utilities
|
|
5
|
+
* Premium query selectors and manipulation tools.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Higher performance querySelector wrapper
|
|
10
|
+
* @param {string} selector
|
|
11
|
+
* @param {HTMLElement|Document} context
|
|
12
|
+
* @returns {HTMLElement|null}
|
|
13
|
+
*/
|
|
14
|
+
const $ = (selector, context = document) => {
|
|
15
|
+
return context.querySelector(selector);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* querySelectorAll wrapper that returns an array instead of a NodeList
|
|
20
|
+
* @param {string} selector
|
|
21
|
+
* @param {HTMLElement|Document} context
|
|
22
|
+
* @returns {HTMLElement[]}
|
|
23
|
+
*/
|
|
24
|
+
const $$ = (selector, context = document) => {
|
|
25
|
+
return Array.from(context.querySelectorAll(selector));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create element with attributes and styles
|
|
30
|
+
* @param {string} tag
|
|
31
|
+
* @param {Object} options
|
|
32
|
+
* @returns {HTMLElement}
|
|
33
|
+
*/
|
|
34
|
+
const create = (tag, options = {}) => {
|
|
35
|
+
const el = document.createElement(tag);
|
|
36
|
+
const {
|
|
37
|
+
attr = {},
|
|
38
|
+
style = {},
|
|
39
|
+
text = "",
|
|
40
|
+
html = "",
|
|
41
|
+
children = [],
|
|
42
|
+
} = options;
|
|
43
|
+
|
|
44
|
+
Object.entries(attr).forEach(([k, v]) => el.setAttribute(k, v));
|
|
45
|
+
Object.assign(el.style, style);
|
|
46
|
+
|
|
47
|
+
if (text) el.textContent = text;
|
|
48
|
+
if (html) el.innerHTML = html;
|
|
49
|
+
|
|
50
|
+
children.forEach((child) => {
|
|
51
|
+
if (child instanceof HTMLElement) el.appendChild(child);
|
|
52
|
+
else el.append(child);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return el;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Event delegation helper
|
|
60
|
+
* @param {HTMLElement|Document} parent
|
|
61
|
+
* @param {string} event
|
|
62
|
+
* @param {string} selector
|
|
63
|
+
* @param {Function} handler
|
|
64
|
+
*/
|
|
65
|
+
const on = (parent, event, selector, handler) => {
|
|
66
|
+
parent.addEventListener(event, (e) => {
|
|
67
|
+
const target = e.target.closest(selector);
|
|
68
|
+
if (target && parent.contains(target)) {
|
|
69
|
+
handler.call(target, e, target);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* HTTP Utilities
|
|
76
|
+
* Clean Fetch API wrapper with easy JSON handling and interceptors.
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
const request = async (url, options = {}) => {
|
|
80
|
+
const {
|
|
81
|
+
method = "GET",
|
|
82
|
+
headers = {},
|
|
83
|
+
body = null,
|
|
84
|
+
interceptors = { request: [], response: [] },
|
|
85
|
+
} = options;
|
|
86
|
+
|
|
87
|
+
let config = {
|
|
88
|
+
method,
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
...headers,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (body && typeof body === "object") {
|
|
96
|
+
config.body = JSON.stringify(body);
|
|
97
|
+
} else if (body) {
|
|
98
|
+
config.body = body;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Request Interceptors
|
|
102
|
+
interceptors.request.forEach((fn) => {
|
|
103
|
+
config = fn(config) || config;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const response = await fetch(url, config);
|
|
108
|
+
let data = await response.json().catch(() => null);
|
|
109
|
+
|
|
110
|
+
// Response Interceptors
|
|
111
|
+
interceptors.response.forEach((fn) => {
|
|
112
|
+
data = fn(data, response) || data;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw { status: response.status, data };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return data;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error("Fetch Error:", error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const http = {
|
|
127
|
+
get: (url, options) => request(url, { ...options, method: "GET" }),
|
|
128
|
+
post: (url, body, options) =>
|
|
129
|
+
request(url, { ...options, method: "POST", body }),
|
|
130
|
+
put: (url, body, options) =>
|
|
131
|
+
request(url, { ...options, method: "PUT", body }),
|
|
132
|
+
delete: (url, options) => request(url, { ...options, method: "DELETE" }),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Storage Utilities
|
|
137
|
+
* Type-safe and auto-serialized local/session storage.
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
const createStorage = (type = "localStorage") => {
|
|
141
|
+
const storage = window[type];
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
/**
|
|
145
|
+
* Set item with auto-serialization
|
|
146
|
+
* @param {string} key
|
|
147
|
+
* @param {any} value
|
|
148
|
+
*/
|
|
149
|
+
set(key, value) {
|
|
150
|
+
try {
|
|
151
|
+
const serialized = JSON.stringify(value);
|
|
152
|
+
storage.setItem(key, serialized);
|
|
153
|
+
} catch (e) {
|
|
154
|
+
console.error(`Storage Error (set): ${key}`, e);
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get item with auto-deserialization
|
|
160
|
+
* @param {string} key
|
|
161
|
+
* @param {any} fallback
|
|
162
|
+
* @returns {any}
|
|
163
|
+
*/
|
|
164
|
+
get(key, fallback = null) {
|
|
165
|
+
try {
|
|
166
|
+
const item = storage.getItem(key);
|
|
167
|
+
return item ? JSON.parse(item) : fallback;
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error(`Storage Error (get): ${key}`, e);
|
|
170
|
+
return fallback;
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Remove item
|
|
176
|
+
* @param {string} key
|
|
177
|
+
*/
|
|
178
|
+
remove(key) {
|
|
179
|
+
storage.removeItem(key);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear all items
|
|
184
|
+
*/
|
|
185
|
+
clear() {
|
|
186
|
+
storage.clear();
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const local = createStorage("localStorage");
|
|
192
|
+
const session = createStorage("sessionStorage");
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* State Management
|
|
196
|
+
* A tiny reactive store (inspired by Svelte stores).
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Creates a reactive store
|
|
201
|
+
* @param {any} initialValue
|
|
202
|
+
* @returns {Object}
|
|
203
|
+
*/
|
|
204
|
+
const createStore = (initialValue) => {
|
|
205
|
+
let value = initialValue;
|
|
206
|
+
const subscribers = new Set();
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Subscribe to changes
|
|
210
|
+
* @param {Function} fn
|
|
211
|
+
* @returns {Function} Unsubscribe function
|
|
212
|
+
*/
|
|
213
|
+
const subscribe = (fn) => {
|
|
214
|
+
subscribers.add(fn);
|
|
215
|
+
fn(value);
|
|
216
|
+
return () => subscribers.delete(fn);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Update value and notify subscribers
|
|
221
|
+
* @param {any|Function} newValue
|
|
222
|
+
*/
|
|
223
|
+
const update = (newValue) => {
|
|
224
|
+
if (typeof newValue === "function") {
|
|
225
|
+
value = newValue(value);
|
|
226
|
+
} else {
|
|
227
|
+
value = newValue;
|
|
228
|
+
}
|
|
229
|
+
subscribers.forEach((fn) => fn(value));
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get current value
|
|
234
|
+
* @returns {any}
|
|
235
|
+
*/
|
|
236
|
+
const get = () => value;
|
|
237
|
+
|
|
238
|
+
return { subscribe, update, get };
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* General Utilities
|
|
243
|
+
* Common helper functions.
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Debounce function
|
|
248
|
+
* @param {Function} fn
|
|
249
|
+
* @param {number} delay
|
|
250
|
+
* @returns {Function}
|
|
251
|
+
*/
|
|
252
|
+
const debounce = (fn, delay = 300) => {
|
|
253
|
+
let timeout;
|
|
254
|
+
return (...args) => {
|
|
255
|
+
clearTimeout(timeout);
|
|
256
|
+
timeout = setTimeout(() => fn.apply(undefined, args), delay);
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Throttle function
|
|
262
|
+
* @param {Function} fn
|
|
263
|
+
* @param {number} limit
|
|
264
|
+
* @returns {Function}
|
|
265
|
+
*/
|
|
266
|
+
const throttle = (fn, limit = 300) => {
|
|
267
|
+
let lastFunc;
|
|
268
|
+
let lastRan;
|
|
269
|
+
return (...args) => {
|
|
270
|
+
if (!lastRan) {
|
|
271
|
+
fn.apply(undefined, args);
|
|
272
|
+
lastRan = Date.now();
|
|
273
|
+
} else {
|
|
274
|
+
clearTimeout(lastFunc);
|
|
275
|
+
lastFunc = setTimeout(
|
|
276
|
+
() => {
|
|
277
|
+
if (Date.now() - lastRan >= limit) {
|
|
278
|
+
fn.apply(undefined, args);
|
|
279
|
+
lastRan = Date.now();
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
limit - (Date.now() - lastRan),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Deep clone an object
|
|
290
|
+
* @param {any} obj
|
|
291
|
+
* @returns {any}
|
|
292
|
+
*/
|
|
293
|
+
const deepClone = (obj) => {
|
|
294
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
295
|
+
return JSON.parse(JSON.stringify(obj));
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Generates a simple UUID-like string
|
|
300
|
+
* @returns {string}
|
|
301
|
+
*/
|
|
302
|
+
const uuid = () => {
|
|
303
|
+
return (
|
|
304
|
+
Math.random().toString(36).substring(2, 10) +
|
|
305
|
+
Date.now().toString(36).substring(2, 6)
|
|
306
|
+
);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Date Utilities
|
|
311
|
+
* Simple and efficient date formatting and manipulation.
|
|
312
|
+
*/
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Basic Date Formatter
|
|
316
|
+
* @param {Date|string|number} date
|
|
317
|
+
* @param {string} pattern - Default: 'YYYY-MM-DD'
|
|
318
|
+
* @returns {string}
|
|
319
|
+
*/
|
|
320
|
+
const formatDate = (date, pattern = "YYYY-MM-DD") => {
|
|
321
|
+
const d = new Date(date);
|
|
322
|
+
if (isNaN(d.getTime())) return "Invalid Date";
|
|
323
|
+
|
|
324
|
+
const map = {
|
|
325
|
+
YYYY: d.getFullYear(),
|
|
326
|
+
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
327
|
+
DD: String(d.getDate()).padStart(2, "0"),
|
|
328
|
+
HH: String(d.getHours()).padStart(2, "0"),
|
|
329
|
+
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
330
|
+
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Returns a human-readable relative time (e.g., "5 minutes ago")
|
|
338
|
+
* @param {Date|string|number} date
|
|
339
|
+
* @returns {string}
|
|
340
|
+
*/
|
|
341
|
+
const relativeTime = (date) => {
|
|
342
|
+
const d = new Date(date);
|
|
343
|
+
const now = new Date();
|
|
344
|
+
const diff = Math.floor((now - d) / 1000);
|
|
345
|
+
|
|
346
|
+
if (diff < 60) return "just now";
|
|
347
|
+
if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;
|
|
348
|
+
if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;
|
|
349
|
+
if (diff < 2592000) return `${Math.floor(diff / 86400)} days ago`;
|
|
350
|
+
|
|
351
|
+
return formatDate(d);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Add days to a date
|
|
356
|
+
* @param {Date|string|number} date
|
|
357
|
+
* @param {number} days
|
|
358
|
+
* @returns {Date}
|
|
359
|
+
*/
|
|
360
|
+
const addDays = (date, days) => {
|
|
361
|
+
const d = new Date(date);
|
|
362
|
+
d.setDate(d.getDate() + days);
|
|
363
|
+
return d;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Check if two dates are the same day
|
|
368
|
+
* @param {Date} d1
|
|
369
|
+
* @param {Date} d2
|
|
370
|
+
* @returns {boolean}
|
|
371
|
+
*/
|
|
372
|
+
const isSameDay = (d1, d2) => {
|
|
373
|
+
return (
|
|
374
|
+
d1.getFullYear() === d2.getFullYear() &&
|
|
375
|
+
d1.getMonth() === d2.getMonth() &&
|
|
376
|
+
d1.getDate() === d2.getDate()
|
|
377
|
+
);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Formatting Utilities
|
|
382
|
+
* Tools for number, currency, and string formatting.
|
|
383
|
+
*/
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Currency Formatter
|
|
387
|
+
* @param {number} amount
|
|
388
|
+
* @param {string} locale - Default: 'id-ID'
|
|
389
|
+
* @param {string} currency - Default: 'IDR'
|
|
390
|
+
* @returns {string}
|
|
391
|
+
*/
|
|
392
|
+
const currency = (amount, locale = "id-ID", currency = "IDR") => {
|
|
393
|
+
return new Intl.NumberFormat(locale, {
|
|
394
|
+
style: "currency",
|
|
395
|
+
currency: currency,
|
|
396
|
+
}).format(amount);
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Number Formatter with decimals
|
|
401
|
+
* @param {number} n
|
|
402
|
+
* @param {number} decimals - Default: 0
|
|
403
|
+
* @returns {string}
|
|
404
|
+
*/
|
|
405
|
+
const number = (n, decimals = 0) => {
|
|
406
|
+
return new Intl.NumberFormat("id-ID", {
|
|
407
|
+
minimumFractionDigits: decimals,
|
|
408
|
+
maximumFractionDigits: decimals,
|
|
409
|
+
}).format(n);
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Truncate string with ellipsis
|
|
414
|
+
* @param {string} str
|
|
415
|
+
* @param {number} length - Default: 30
|
|
416
|
+
* @returns {string}
|
|
417
|
+
*/
|
|
418
|
+
const truncate = (str, length = 30) => {
|
|
419
|
+
if (!str) return "";
|
|
420
|
+
return str.length > length ? str.substring(0, length) + "..." : str;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Convert string to slug (URL friendly)
|
|
425
|
+
* @param {string} str
|
|
426
|
+
* @returns {string}
|
|
427
|
+
*/
|
|
428
|
+
const slugify = (str) => {
|
|
429
|
+
if (!str) return "";
|
|
430
|
+
return str
|
|
431
|
+
.toLowerCase()
|
|
432
|
+
.trim()
|
|
433
|
+
.replace(/[^\w\s-]/g, "")
|
|
434
|
+
.replace(/[\s_-]+/g, "-")
|
|
435
|
+
.replace(/^-+|-+$/g, "");
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Capitalize first letter of each word
|
|
440
|
+
* @param {string} str
|
|
441
|
+
* @returns {string}
|
|
442
|
+
*/
|
|
443
|
+
const capitalize = (str) => {
|
|
444
|
+
if (!str) return "";
|
|
445
|
+
return str.replace(/\b\w/g, (l) => l.toUpperCase());
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Validation Utilities
|
|
450
|
+
* Common regex-based validation helpers.
|
|
451
|
+
*/
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Check if string is a valid email
|
|
455
|
+
* @param {string} str
|
|
456
|
+
* @returns {boolean}
|
|
457
|
+
*/
|
|
458
|
+
const isEmail = (str) => {
|
|
459
|
+
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
460
|
+
return re.test(str);
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Check if string is a valid URL
|
|
465
|
+
* @param {string} str
|
|
466
|
+
* @returns {boolean}
|
|
467
|
+
*/
|
|
468
|
+
const isURL = (str) => {
|
|
469
|
+
try {
|
|
470
|
+
new URL(str);
|
|
471
|
+
return true;
|
|
472
|
+
} catch {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Check if string contains only numbers
|
|
479
|
+
* @param {string} str
|
|
480
|
+
* @returns {boolean}
|
|
481
|
+
*/
|
|
482
|
+
const isNumeric = (str) => {
|
|
483
|
+
return /^\d+$/.test(str);
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Check for strong password
|
|
488
|
+
* (Min 8 chars, 1 uppercase, 1 lowercase, 1 number)
|
|
489
|
+
* @param {string} str
|
|
490
|
+
* @returns {boolean}
|
|
491
|
+
*/
|
|
492
|
+
const isStrongPassword = (str) => {
|
|
493
|
+
return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(str);
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Check if string is empty or only whitespace
|
|
498
|
+
* @param {string} str
|
|
499
|
+
* @returns {boolean}
|
|
500
|
+
*/
|
|
501
|
+
const isEmpty = (str) => {
|
|
502
|
+
return !str || str.trim().length === 0;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
exports.$ = $;
|
|
506
|
+
exports.$$ = $$;
|
|
507
|
+
exports.addDays = addDays;
|
|
508
|
+
exports.capitalize = capitalize;
|
|
509
|
+
exports.create = create;
|
|
510
|
+
exports.createStore = createStore;
|
|
511
|
+
exports.currency = currency;
|
|
512
|
+
exports.debounce = debounce;
|
|
513
|
+
exports.deepClone = deepClone;
|
|
514
|
+
exports.formatDate = formatDate;
|
|
515
|
+
exports.http = http;
|
|
516
|
+
exports.isEmail = isEmail;
|
|
517
|
+
exports.isEmpty = isEmpty;
|
|
518
|
+
exports.isNumeric = isNumeric;
|
|
519
|
+
exports.isSameDay = isSameDay;
|
|
520
|
+
exports.isStrongPassword = isStrongPassword;
|
|
521
|
+
exports.isURL = isURL;
|
|
522
|
+
exports.local = local;
|
|
523
|
+
exports.number = number;
|
|
524
|
+
exports.on = on;
|
|
525
|
+
exports.relativeTime = relativeTime;
|
|
526
|
+
exports.session = session;
|
|
527
|
+
exports.slugify = slugify;
|
|
528
|
+
exports.throttle = throttle;
|
|
529
|
+
exports.truncate = truncate;
|
|
530
|
+
exports.uuid = uuid;
|
|
531
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/dom.js","../src/http.js","../src/storage.js","../src/state.js","../src/utils.js","../src/date.js","../src/format.js","../src/validation.js"],"sourcesContent":["/**\r\n * DOM Utilities\r\n * Premium query selectors and manipulation tools.\r\n */\r\n\r\n/**\r\n * Higher performance querySelector wrapper\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement|null}\r\n */\r\nexport const $ = (selector, context = document) => {\r\n return context.querySelector(selector);\r\n};\r\n\r\n/**\r\n * querySelectorAll wrapper that returns an array instead of a NodeList\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement[]}\r\n */\r\nexport const $$ = (selector, context = document) => {\r\n return Array.from(context.querySelectorAll(selector));\r\n};\r\n\r\n/**\r\n * Create element with attributes and styles\r\n * @param {string} tag\r\n * @param {Object} options\r\n * @returns {HTMLElement}\r\n */\r\nexport const create = (tag, options = {}) => {\r\n const el = document.createElement(tag);\r\n const {\r\n attr = {},\r\n style = {},\r\n text = \"\",\r\n html = \"\",\r\n children = [],\r\n } = options;\r\n\r\n Object.entries(attr).forEach(([k, v]) => el.setAttribute(k, v));\r\n Object.assign(el.style, style);\r\n\r\n if (text) el.textContent = text;\r\n if (html) el.innerHTML = html;\r\n\r\n children.forEach((child) => {\r\n if (child instanceof HTMLElement) el.appendChild(child);\r\n else el.append(child);\r\n });\r\n\r\n return el;\r\n};\r\n\r\n/**\r\n * Event delegation helper\r\n * @param {HTMLElement|Document} parent\r\n * @param {string} event\r\n * @param {string} selector\r\n * @param {Function} handler\r\n */\r\nexport const on = (parent, event, selector, handler) => {\r\n parent.addEventListener(event, (e) => {\r\n const target = e.target.closest(selector);\r\n if (target && parent.contains(target)) {\r\n handler.call(target, e, target);\r\n }\r\n });\r\n};\r\n","/**\r\n * HTTP Utilities\r\n * Clean Fetch API wrapper with easy JSON handling and interceptors.\r\n */\r\n\r\nconst request = async (url, options = {}) => {\r\n const {\r\n method = \"GET\",\r\n headers = {},\r\n body = null,\r\n interceptors = { request: [], response: [] },\r\n } = options;\r\n\r\n let config = {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n };\r\n\r\n if (body && typeof body === \"object\") {\r\n config.body = JSON.stringify(body);\r\n } else if (body) {\r\n config.body = body;\r\n }\r\n\r\n // Request Interceptors\r\n interceptors.request.forEach((fn) => {\r\n config = fn(config) || config;\r\n });\r\n\r\n try {\r\n const response = await fetch(url, config);\r\n let data = await response.json().catch(() => null);\r\n\r\n // Response Interceptors\r\n interceptors.response.forEach((fn) => {\r\n data = fn(data, response) || data;\r\n });\r\n\r\n if (!response.ok) {\r\n throw { status: response.status, data };\r\n }\r\n\r\n return data;\r\n } catch (error) {\r\n console.error(\"Fetch Error:\", error);\r\n throw error;\r\n }\r\n};\r\n\r\nexport const http = {\r\n get: (url, options) => request(url, { ...options, method: \"GET\" }),\r\n post: (url, body, options) =>\r\n request(url, { ...options, method: \"POST\", body }),\r\n put: (url, body, options) =>\r\n request(url, { ...options, method: \"PUT\", body }),\r\n delete: (url, options) => request(url, { ...options, method: \"DELETE\" }),\r\n};\r\n","/**\r\n * Storage Utilities\r\n * Type-safe and auto-serialized local/session storage.\r\n */\r\n\r\nconst createStorage = (type = \"localStorage\") => {\r\n const storage = window[type];\r\n\r\n return {\r\n /**\r\n * Set item with auto-serialization\r\n * @param {string} key\r\n * @param {any} value\r\n */\r\n set(key, value) {\r\n try {\r\n const serialized = JSON.stringify(value);\r\n storage.setItem(key, serialized);\r\n } catch (e) {\r\n console.error(`Storage Error (set): ${key}`, e);\r\n }\r\n },\r\n\r\n /**\r\n * Get item with auto-deserialization\r\n * @param {string} key\r\n * @param {any} fallback\r\n * @returns {any}\r\n */\r\n get(key, fallback = null) {\r\n try {\r\n const item = storage.getItem(key);\r\n return item ? JSON.parse(item) : fallback;\r\n } catch (e) {\r\n console.error(`Storage Error (get): ${key}`, e);\r\n return fallback;\r\n }\r\n },\r\n\r\n /**\r\n * Remove item\r\n * @param {string} key\r\n */\r\n remove(key) {\r\n storage.removeItem(key);\r\n },\r\n\r\n /**\r\n * Clear all items\r\n */\r\n clear() {\r\n storage.clear();\r\n },\r\n };\r\n};\r\n\r\nexport const local = createStorage(\"localStorage\");\r\nexport const session = createStorage(\"sessionStorage\");\r\n","/**\r\n * State Management\r\n * A tiny reactive store (inspired by Svelte stores).\r\n */\r\n\r\n/**\r\n * Creates a reactive store\r\n * @param {any} initialValue\r\n * @returns {Object}\r\n */\r\nexport const createStore = (initialValue) => {\r\n let value = initialValue;\r\n const subscribers = new Set();\r\n\r\n /**\r\n * Subscribe to changes\r\n * @param {Function} fn\r\n * @returns {Function} Unsubscribe function\r\n */\r\n const subscribe = (fn) => {\r\n subscribers.add(fn);\r\n fn(value);\r\n return () => subscribers.delete(fn);\r\n };\r\n\r\n /**\r\n * Update value and notify subscribers\r\n * @param {any|Function} newValue\r\n */\r\n const update = (newValue) => {\r\n if (typeof newValue === \"function\") {\r\n value = newValue(value);\r\n } else {\r\n value = newValue;\r\n }\r\n subscribers.forEach((fn) => fn(value));\r\n };\r\n\r\n /**\r\n * Get current value\r\n * @returns {any}\r\n */\r\n const get = () => value;\r\n\r\n return { subscribe, update, get };\r\n};\r\n","/**\r\n * General Utilities\r\n * Common helper functions.\r\n */\r\n\r\n/**\r\n * Debounce function\r\n * @param {Function} fn\r\n * @param {number} delay\r\n * @returns {Function}\r\n */\r\nexport const debounce = (fn, delay = 300) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => fn.apply(this, args), delay);\r\n };\r\n};\r\n\r\n/**\r\n * Throttle function\r\n * @param {Function} fn\r\n * @param {number} limit\r\n * @returns {Function}\r\n */\r\nexport const throttle = (fn, limit = 300) => {\r\n let lastFunc;\r\n let lastRan;\r\n return (...args) => {\r\n if (!lastRan) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n } else {\r\n clearTimeout(lastFunc);\r\n lastFunc = setTimeout(\r\n () => {\r\n if (Date.now() - lastRan >= limit) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n }\r\n },\r\n limit - (Date.now() - lastRan),\r\n );\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Deep clone an object\r\n * @param {any} obj\r\n * @returns {any}\r\n */\r\nexport const deepClone = (obj) => {\r\n if (obj === null || typeof obj !== \"object\") return obj;\r\n return JSON.parse(JSON.stringify(obj));\r\n};\r\n\r\n/**\r\n * Generates a simple UUID-like string\r\n * @returns {string}\r\n */\r\nexport const uuid = () => {\r\n return (\r\n Math.random().toString(36).substring(2, 10) +\r\n Date.now().toString(36).substring(2, 6)\r\n );\r\n};\r\n","/**\r\n * Date Utilities\r\n * Simple and efficient date formatting and manipulation.\r\n */\r\n\r\n/**\r\n * Basic Date Formatter\r\n * @param {Date|string|number} date\r\n * @param {string} pattern - Default: 'YYYY-MM-DD'\r\n * @returns {string}\r\n */\r\nexport const formatDate = (date, pattern = \"YYYY-MM-DD\") => {\r\n const d = new Date(date);\r\n if (isNaN(d.getTime())) return \"Invalid Date\";\r\n\r\n const map = {\r\n YYYY: d.getFullYear(),\r\n MM: String(d.getMonth() + 1).padStart(2, \"0\"),\r\n DD: String(d.getDate()).padStart(2, \"0\"),\r\n HH: String(d.getHours()).padStart(2, \"0\"),\r\n mm: String(d.getMinutes()).padStart(2, \"0\"),\r\n ss: String(d.getSeconds()).padStart(2, \"0\"),\r\n };\r\n\r\n return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);\r\n};\r\n\r\n/**\r\n * Returns a human-readable relative time (e.g., \"5 minutes ago\")\r\n * @param {Date|string|number} date\r\n * @returns {string}\r\n */\r\nexport const relativeTime = (date) => {\r\n const d = new Date(date);\r\n const now = new Date();\r\n const diff = Math.floor((now - d) / 1000);\r\n\r\n if (diff < 60) return \"just now\";\r\n if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;\r\n if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;\r\n if (diff < 2592000) return `${Math.floor(diff / 86400)} days ago`;\r\n\r\n return formatDate(d);\r\n};\r\n\r\n/**\r\n * Add days to a date\r\n * @param {Date|string|number} date\r\n * @param {number} days\r\n * @returns {Date}\r\n */\r\nexport const addDays = (date, days) => {\r\n const d = new Date(date);\r\n d.setDate(d.getDate() + days);\r\n return d;\r\n};\r\n\r\n/**\r\n * Check if two dates are the same day\r\n * @param {Date} d1\r\n * @param {Date} d2\r\n * @returns {boolean}\r\n */\r\nexport const isSameDay = (d1, d2) => {\r\n return (\r\n d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n );\r\n};\r\n","/**\r\n * Formatting Utilities\r\n * Tools for number, currency, and string formatting.\r\n */\r\n\r\n/**\r\n * Currency Formatter\r\n * @param {number} amount\r\n * @param {string} locale - Default: 'id-ID'\r\n * @param {string} currency - Default: 'IDR'\r\n * @returns {string}\r\n */\r\nexport const currency = (amount, locale = \"id-ID\", currency = \"IDR\") => {\r\n return new Intl.NumberFormat(locale, {\r\n style: \"currency\",\r\n currency: currency,\r\n }).format(amount);\r\n};\r\n\r\n/**\r\n * Number Formatter with decimals\r\n * @param {number} n\r\n * @param {number} decimals - Default: 0\r\n * @returns {string}\r\n */\r\nexport const number = (n, decimals = 0) => {\r\n return new Intl.NumberFormat(\"id-ID\", {\r\n minimumFractionDigits: decimals,\r\n maximumFractionDigits: decimals,\r\n }).format(n);\r\n};\r\n\r\n/**\r\n * Truncate string with ellipsis\r\n * @param {string} str\r\n * @param {number} length - Default: 30\r\n * @returns {string}\r\n */\r\nexport const truncate = (str, length = 30) => {\r\n if (!str) return \"\";\r\n return str.length > length ? str.substring(0, length) + \"...\" : str;\r\n};\r\n\r\n/**\r\n * Convert string to slug (URL friendly)\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const slugify = (str) => {\r\n if (!str) return \"\";\r\n return str\r\n .toLowerCase()\r\n .trim()\r\n .replace(/[^\\w\\s-]/g, \"\")\r\n .replace(/[\\s_-]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n};\r\n\r\n/**\r\n * Capitalize first letter of each word\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const capitalize = (str) => {\r\n if (!str) return \"\";\r\n return str.replace(/\\b\\w/g, (l) => l.toUpperCase());\r\n};\r\n","/**\r\n * Validation Utilities\r\n * Common regex-based validation helpers.\r\n */\r\n\r\n/**\r\n * Check if string is a valid email\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmail = (str) => {\r\n const re = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n return re.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is a valid URL\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isURL = (str) => {\r\n try {\r\n new URL(str);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Check if string contains only numbers\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isNumeric = (str) => {\r\n return /^\\d+$/.test(str);\r\n};\r\n\r\n/**\r\n * Check for strong password\r\n * (Min 8 chars, 1 uppercase, 1 lowercase, 1 number)\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isStrongPassword = (str) => {\r\n return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is empty or only whitespace\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmpty = (str) => {\r\n return !str || str.trim().length === 0;\r\n};\r\n"],"names":["this"],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM Utilities
|
|
3
|
+
* Premium query selectors and manipulation tools.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Higher performance querySelector wrapper
|
|
8
|
+
* @param {string} selector
|
|
9
|
+
* @param {HTMLElement|Document} context
|
|
10
|
+
* @returns {HTMLElement|null}
|
|
11
|
+
*/
|
|
12
|
+
const $ = (selector, context = document) => {
|
|
13
|
+
return context.querySelector(selector);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* querySelectorAll wrapper that returns an array instead of a NodeList
|
|
18
|
+
* @param {string} selector
|
|
19
|
+
* @param {HTMLElement|Document} context
|
|
20
|
+
* @returns {HTMLElement[]}
|
|
21
|
+
*/
|
|
22
|
+
const $$ = (selector, context = document) => {
|
|
23
|
+
return Array.from(context.querySelectorAll(selector));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create element with attributes and styles
|
|
28
|
+
* @param {string} tag
|
|
29
|
+
* @param {Object} options
|
|
30
|
+
* @returns {HTMLElement}
|
|
31
|
+
*/
|
|
32
|
+
const create = (tag, options = {}) => {
|
|
33
|
+
const el = document.createElement(tag);
|
|
34
|
+
const {
|
|
35
|
+
attr = {},
|
|
36
|
+
style = {},
|
|
37
|
+
text = "",
|
|
38
|
+
html = "",
|
|
39
|
+
children = [],
|
|
40
|
+
} = options;
|
|
41
|
+
|
|
42
|
+
Object.entries(attr).forEach(([k, v]) => el.setAttribute(k, v));
|
|
43
|
+
Object.assign(el.style, style);
|
|
44
|
+
|
|
45
|
+
if (text) el.textContent = text;
|
|
46
|
+
if (html) el.innerHTML = html;
|
|
47
|
+
|
|
48
|
+
children.forEach((child) => {
|
|
49
|
+
if (child instanceof HTMLElement) el.appendChild(child);
|
|
50
|
+
else el.append(child);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return el;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Event delegation helper
|
|
58
|
+
* @param {HTMLElement|Document} parent
|
|
59
|
+
* @param {string} event
|
|
60
|
+
* @param {string} selector
|
|
61
|
+
* @param {Function} handler
|
|
62
|
+
*/
|
|
63
|
+
const on = (parent, event, selector, handler) => {
|
|
64
|
+
parent.addEventListener(event, (e) => {
|
|
65
|
+
const target = e.target.closest(selector);
|
|
66
|
+
if (target && parent.contains(target)) {
|
|
67
|
+
handler.call(target, e, target);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* HTTP Utilities
|
|
74
|
+
* Clean Fetch API wrapper with easy JSON handling and interceptors.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
const request = async (url, options = {}) => {
|
|
78
|
+
const {
|
|
79
|
+
method = "GET",
|
|
80
|
+
headers = {},
|
|
81
|
+
body = null,
|
|
82
|
+
interceptors = { request: [], response: [] },
|
|
83
|
+
} = options;
|
|
84
|
+
|
|
85
|
+
let config = {
|
|
86
|
+
method,
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/json",
|
|
89
|
+
...headers,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (body && typeof body === "object") {
|
|
94
|
+
config.body = JSON.stringify(body);
|
|
95
|
+
} else if (body) {
|
|
96
|
+
config.body = body;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Request Interceptors
|
|
100
|
+
interceptors.request.forEach((fn) => {
|
|
101
|
+
config = fn(config) || config;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const response = await fetch(url, config);
|
|
106
|
+
let data = await response.json().catch(() => null);
|
|
107
|
+
|
|
108
|
+
// Response Interceptors
|
|
109
|
+
interceptors.response.forEach((fn) => {
|
|
110
|
+
data = fn(data, response) || data;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
throw { status: response.status, data };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return data;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("Fetch Error:", error);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const http = {
|
|
125
|
+
get: (url, options) => request(url, { ...options, method: "GET" }),
|
|
126
|
+
post: (url, body, options) =>
|
|
127
|
+
request(url, { ...options, method: "POST", body }),
|
|
128
|
+
put: (url, body, options) =>
|
|
129
|
+
request(url, { ...options, method: "PUT", body }),
|
|
130
|
+
delete: (url, options) => request(url, { ...options, method: "DELETE" }),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Storage Utilities
|
|
135
|
+
* Type-safe and auto-serialized local/session storage.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
const createStorage = (type = "localStorage") => {
|
|
139
|
+
const storage = window[type];
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
/**
|
|
143
|
+
* Set item with auto-serialization
|
|
144
|
+
* @param {string} key
|
|
145
|
+
* @param {any} value
|
|
146
|
+
*/
|
|
147
|
+
set(key, value) {
|
|
148
|
+
try {
|
|
149
|
+
const serialized = JSON.stringify(value);
|
|
150
|
+
storage.setItem(key, serialized);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
console.error(`Storage Error (set): ${key}`, e);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get item with auto-deserialization
|
|
158
|
+
* @param {string} key
|
|
159
|
+
* @param {any} fallback
|
|
160
|
+
* @returns {any}
|
|
161
|
+
*/
|
|
162
|
+
get(key, fallback = null) {
|
|
163
|
+
try {
|
|
164
|
+
const item = storage.getItem(key);
|
|
165
|
+
return item ? JSON.parse(item) : fallback;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
console.error(`Storage Error (get): ${key}`, e);
|
|
168
|
+
return fallback;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Remove item
|
|
174
|
+
* @param {string} key
|
|
175
|
+
*/
|
|
176
|
+
remove(key) {
|
|
177
|
+
storage.removeItem(key);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Clear all items
|
|
182
|
+
*/
|
|
183
|
+
clear() {
|
|
184
|
+
storage.clear();
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const local = createStorage("localStorage");
|
|
190
|
+
const session = createStorage("sessionStorage");
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* State Management
|
|
194
|
+
* A tiny reactive store (inspired by Svelte stores).
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates a reactive store
|
|
199
|
+
* @param {any} initialValue
|
|
200
|
+
* @returns {Object}
|
|
201
|
+
*/
|
|
202
|
+
const createStore = (initialValue) => {
|
|
203
|
+
let value = initialValue;
|
|
204
|
+
const subscribers = new Set();
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Subscribe to changes
|
|
208
|
+
* @param {Function} fn
|
|
209
|
+
* @returns {Function} Unsubscribe function
|
|
210
|
+
*/
|
|
211
|
+
const subscribe = (fn) => {
|
|
212
|
+
subscribers.add(fn);
|
|
213
|
+
fn(value);
|
|
214
|
+
return () => subscribers.delete(fn);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Update value and notify subscribers
|
|
219
|
+
* @param {any|Function} newValue
|
|
220
|
+
*/
|
|
221
|
+
const update = (newValue) => {
|
|
222
|
+
if (typeof newValue === "function") {
|
|
223
|
+
value = newValue(value);
|
|
224
|
+
} else {
|
|
225
|
+
value = newValue;
|
|
226
|
+
}
|
|
227
|
+
subscribers.forEach((fn) => fn(value));
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get current value
|
|
232
|
+
* @returns {any}
|
|
233
|
+
*/
|
|
234
|
+
const get = () => value;
|
|
235
|
+
|
|
236
|
+
return { subscribe, update, get };
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* General Utilities
|
|
241
|
+
* Common helper functions.
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Debounce function
|
|
246
|
+
* @param {Function} fn
|
|
247
|
+
* @param {number} delay
|
|
248
|
+
* @returns {Function}
|
|
249
|
+
*/
|
|
250
|
+
const debounce = (fn, delay = 300) => {
|
|
251
|
+
let timeout;
|
|
252
|
+
return (...args) => {
|
|
253
|
+
clearTimeout(timeout);
|
|
254
|
+
timeout = setTimeout(() => fn.apply(undefined, args), delay);
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Throttle function
|
|
260
|
+
* @param {Function} fn
|
|
261
|
+
* @param {number} limit
|
|
262
|
+
* @returns {Function}
|
|
263
|
+
*/
|
|
264
|
+
const throttle = (fn, limit = 300) => {
|
|
265
|
+
let lastFunc;
|
|
266
|
+
let lastRan;
|
|
267
|
+
return (...args) => {
|
|
268
|
+
if (!lastRan) {
|
|
269
|
+
fn.apply(undefined, args);
|
|
270
|
+
lastRan = Date.now();
|
|
271
|
+
} else {
|
|
272
|
+
clearTimeout(lastFunc);
|
|
273
|
+
lastFunc = setTimeout(
|
|
274
|
+
() => {
|
|
275
|
+
if (Date.now() - lastRan >= limit) {
|
|
276
|
+
fn.apply(undefined, args);
|
|
277
|
+
lastRan = Date.now();
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
limit - (Date.now() - lastRan),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Deep clone an object
|
|
288
|
+
* @param {any} obj
|
|
289
|
+
* @returns {any}
|
|
290
|
+
*/
|
|
291
|
+
const deepClone = (obj) => {
|
|
292
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
293
|
+
return JSON.parse(JSON.stringify(obj));
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generates a simple UUID-like string
|
|
298
|
+
* @returns {string}
|
|
299
|
+
*/
|
|
300
|
+
const uuid = () => {
|
|
301
|
+
return (
|
|
302
|
+
Math.random().toString(36).substring(2, 10) +
|
|
303
|
+
Date.now().toString(36).substring(2, 6)
|
|
304
|
+
);
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Date Utilities
|
|
309
|
+
* Simple and efficient date formatting and manipulation.
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Basic Date Formatter
|
|
314
|
+
* @param {Date|string|number} date
|
|
315
|
+
* @param {string} pattern - Default: 'YYYY-MM-DD'
|
|
316
|
+
* @returns {string}
|
|
317
|
+
*/
|
|
318
|
+
const formatDate = (date, pattern = "YYYY-MM-DD") => {
|
|
319
|
+
const d = new Date(date);
|
|
320
|
+
if (isNaN(d.getTime())) return "Invalid Date";
|
|
321
|
+
|
|
322
|
+
const map = {
|
|
323
|
+
YYYY: d.getFullYear(),
|
|
324
|
+
MM: String(d.getMonth() + 1).padStart(2, "0"),
|
|
325
|
+
DD: String(d.getDate()).padStart(2, "0"),
|
|
326
|
+
HH: String(d.getHours()).padStart(2, "0"),
|
|
327
|
+
mm: String(d.getMinutes()).padStart(2, "0"),
|
|
328
|
+
ss: String(d.getSeconds()).padStart(2, "0"),
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Returns a human-readable relative time (e.g., "5 minutes ago")
|
|
336
|
+
* @param {Date|string|number} date
|
|
337
|
+
* @returns {string}
|
|
338
|
+
*/
|
|
339
|
+
const relativeTime = (date) => {
|
|
340
|
+
const d = new Date(date);
|
|
341
|
+
const now = new Date();
|
|
342
|
+
const diff = Math.floor((now - d) / 1000);
|
|
343
|
+
|
|
344
|
+
if (diff < 60) return "just now";
|
|
345
|
+
if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;
|
|
346
|
+
if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;
|
|
347
|
+
if (diff < 2592000) return `${Math.floor(diff / 86400)} days ago`;
|
|
348
|
+
|
|
349
|
+
return formatDate(d);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Add days to a date
|
|
354
|
+
* @param {Date|string|number} date
|
|
355
|
+
* @param {number} days
|
|
356
|
+
* @returns {Date}
|
|
357
|
+
*/
|
|
358
|
+
const addDays = (date, days) => {
|
|
359
|
+
const d = new Date(date);
|
|
360
|
+
d.setDate(d.getDate() + days);
|
|
361
|
+
return d;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Check if two dates are the same day
|
|
366
|
+
* @param {Date} d1
|
|
367
|
+
* @param {Date} d2
|
|
368
|
+
* @returns {boolean}
|
|
369
|
+
*/
|
|
370
|
+
const isSameDay = (d1, d2) => {
|
|
371
|
+
return (
|
|
372
|
+
d1.getFullYear() === d2.getFullYear() &&
|
|
373
|
+
d1.getMonth() === d2.getMonth() &&
|
|
374
|
+
d1.getDate() === d2.getDate()
|
|
375
|
+
);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Formatting Utilities
|
|
380
|
+
* Tools for number, currency, and string formatting.
|
|
381
|
+
*/
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Currency Formatter
|
|
385
|
+
* @param {number} amount
|
|
386
|
+
* @param {string} locale - Default: 'id-ID'
|
|
387
|
+
* @param {string} currency - Default: 'IDR'
|
|
388
|
+
* @returns {string}
|
|
389
|
+
*/
|
|
390
|
+
const currency = (amount, locale = "id-ID", currency = "IDR") => {
|
|
391
|
+
return new Intl.NumberFormat(locale, {
|
|
392
|
+
style: "currency",
|
|
393
|
+
currency: currency,
|
|
394
|
+
}).format(amount);
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Number Formatter with decimals
|
|
399
|
+
* @param {number} n
|
|
400
|
+
* @param {number} decimals - Default: 0
|
|
401
|
+
* @returns {string}
|
|
402
|
+
*/
|
|
403
|
+
const number = (n, decimals = 0) => {
|
|
404
|
+
return new Intl.NumberFormat("id-ID", {
|
|
405
|
+
minimumFractionDigits: decimals,
|
|
406
|
+
maximumFractionDigits: decimals,
|
|
407
|
+
}).format(n);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Truncate string with ellipsis
|
|
412
|
+
* @param {string} str
|
|
413
|
+
* @param {number} length - Default: 30
|
|
414
|
+
* @returns {string}
|
|
415
|
+
*/
|
|
416
|
+
const truncate = (str, length = 30) => {
|
|
417
|
+
if (!str) return "";
|
|
418
|
+
return str.length > length ? str.substring(0, length) + "..." : str;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Convert string to slug (URL friendly)
|
|
423
|
+
* @param {string} str
|
|
424
|
+
* @returns {string}
|
|
425
|
+
*/
|
|
426
|
+
const slugify = (str) => {
|
|
427
|
+
if (!str) return "";
|
|
428
|
+
return str
|
|
429
|
+
.toLowerCase()
|
|
430
|
+
.trim()
|
|
431
|
+
.replace(/[^\w\s-]/g, "")
|
|
432
|
+
.replace(/[\s_-]+/g, "-")
|
|
433
|
+
.replace(/^-+|-+$/g, "");
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Capitalize first letter of each word
|
|
438
|
+
* @param {string} str
|
|
439
|
+
* @returns {string}
|
|
440
|
+
*/
|
|
441
|
+
const capitalize = (str) => {
|
|
442
|
+
if (!str) return "";
|
|
443
|
+
return str.replace(/\b\w/g, (l) => l.toUpperCase());
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Validation Utilities
|
|
448
|
+
* Common regex-based validation helpers.
|
|
449
|
+
*/
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Check if string is a valid email
|
|
453
|
+
* @param {string} str
|
|
454
|
+
* @returns {boolean}
|
|
455
|
+
*/
|
|
456
|
+
const isEmail = (str) => {
|
|
457
|
+
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
458
|
+
return re.test(str);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Check if string is a valid URL
|
|
463
|
+
* @param {string} str
|
|
464
|
+
* @returns {boolean}
|
|
465
|
+
*/
|
|
466
|
+
const isURL = (str) => {
|
|
467
|
+
try {
|
|
468
|
+
new URL(str);
|
|
469
|
+
return true;
|
|
470
|
+
} catch {
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Check if string contains only numbers
|
|
477
|
+
* @param {string} str
|
|
478
|
+
* @returns {boolean}
|
|
479
|
+
*/
|
|
480
|
+
const isNumeric = (str) => {
|
|
481
|
+
return /^\d+$/.test(str);
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Check for strong password
|
|
486
|
+
* (Min 8 chars, 1 uppercase, 1 lowercase, 1 number)
|
|
487
|
+
* @param {string} str
|
|
488
|
+
* @returns {boolean}
|
|
489
|
+
*/
|
|
490
|
+
const isStrongPassword = (str) => {
|
|
491
|
+
return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(str);
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Check if string is empty or only whitespace
|
|
496
|
+
* @param {string} str
|
|
497
|
+
* @returns {boolean}
|
|
498
|
+
*/
|
|
499
|
+
const isEmpty = (str) => {
|
|
500
|
+
return !str || str.trim().length === 0;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
export { $, $$, addDays, capitalize, create, createStore, currency, debounce, deepClone, formatDate, http, isEmail, isEmpty, isNumeric, isSameDay, isStrongPassword, isURL, local, number, on, relativeTime, session, slugify, throttle, truncate, uuid };
|
|
504
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/dom.js","../src/http.js","../src/storage.js","../src/state.js","../src/utils.js","../src/date.js","../src/format.js","../src/validation.js"],"sourcesContent":["/**\r\n * DOM Utilities\r\n * Premium query selectors and manipulation tools.\r\n */\r\n\r\n/**\r\n * Higher performance querySelector wrapper\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement|null}\r\n */\r\nexport const $ = (selector, context = document) => {\r\n return context.querySelector(selector);\r\n};\r\n\r\n/**\r\n * querySelectorAll wrapper that returns an array instead of a NodeList\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement[]}\r\n */\r\nexport const $$ = (selector, context = document) => {\r\n return Array.from(context.querySelectorAll(selector));\r\n};\r\n\r\n/**\r\n * Create element with attributes and styles\r\n * @param {string} tag\r\n * @param {Object} options\r\n * @returns {HTMLElement}\r\n */\r\nexport const create = (tag, options = {}) => {\r\n const el = document.createElement(tag);\r\n const {\r\n attr = {},\r\n style = {},\r\n text = \"\",\r\n html = \"\",\r\n children = [],\r\n } = options;\r\n\r\n Object.entries(attr).forEach(([k, v]) => el.setAttribute(k, v));\r\n Object.assign(el.style, style);\r\n\r\n if (text) el.textContent = text;\r\n if (html) el.innerHTML = html;\r\n\r\n children.forEach((child) => {\r\n if (child instanceof HTMLElement) el.appendChild(child);\r\n else el.append(child);\r\n });\r\n\r\n return el;\r\n};\r\n\r\n/**\r\n * Event delegation helper\r\n * @param {HTMLElement|Document} parent\r\n * @param {string} event\r\n * @param {string} selector\r\n * @param {Function} handler\r\n */\r\nexport const on = (parent, event, selector, handler) => {\r\n parent.addEventListener(event, (e) => {\r\n const target = e.target.closest(selector);\r\n if (target && parent.contains(target)) {\r\n handler.call(target, e, target);\r\n }\r\n });\r\n};\r\n","/**\r\n * HTTP Utilities\r\n * Clean Fetch API wrapper with easy JSON handling and interceptors.\r\n */\r\n\r\nconst request = async (url, options = {}) => {\r\n const {\r\n method = \"GET\",\r\n headers = {},\r\n body = null,\r\n interceptors = { request: [], response: [] },\r\n } = options;\r\n\r\n let config = {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n };\r\n\r\n if (body && typeof body === \"object\") {\r\n config.body = JSON.stringify(body);\r\n } else if (body) {\r\n config.body = body;\r\n }\r\n\r\n // Request Interceptors\r\n interceptors.request.forEach((fn) => {\r\n config = fn(config) || config;\r\n });\r\n\r\n try {\r\n const response = await fetch(url, config);\r\n let data = await response.json().catch(() => null);\r\n\r\n // Response Interceptors\r\n interceptors.response.forEach((fn) => {\r\n data = fn(data, response) || data;\r\n });\r\n\r\n if (!response.ok) {\r\n throw { status: response.status, data };\r\n }\r\n\r\n return data;\r\n } catch (error) {\r\n console.error(\"Fetch Error:\", error);\r\n throw error;\r\n }\r\n};\r\n\r\nexport const http = {\r\n get: (url, options) => request(url, { ...options, method: \"GET\" }),\r\n post: (url, body, options) =>\r\n request(url, { ...options, method: \"POST\", body }),\r\n put: (url, body, options) =>\r\n request(url, { ...options, method: \"PUT\", body }),\r\n delete: (url, options) => request(url, { ...options, method: \"DELETE\" }),\r\n};\r\n","/**\r\n * Storage Utilities\r\n * Type-safe and auto-serialized local/session storage.\r\n */\r\n\r\nconst createStorage = (type = \"localStorage\") => {\r\n const storage = window[type];\r\n\r\n return {\r\n /**\r\n * Set item with auto-serialization\r\n * @param {string} key\r\n * @param {any} value\r\n */\r\n set(key, value) {\r\n try {\r\n const serialized = JSON.stringify(value);\r\n storage.setItem(key, serialized);\r\n } catch (e) {\r\n console.error(`Storage Error (set): ${key}`, e);\r\n }\r\n },\r\n\r\n /**\r\n * Get item with auto-deserialization\r\n * @param {string} key\r\n * @param {any} fallback\r\n * @returns {any}\r\n */\r\n get(key, fallback = null) {\r\n try {\r\n const item = storage.getItem(key);\r\n return item ? JSON.parse(item) : fallback;\r\n } catch (e) {\r\n console.error(`Storage Error (get): ${key}`, e);\r\n return fallback;\r\n }\r\n },\r\n\r\n /**\r\n * Remove item\r\n * @param {string} key\r\n */\r\n remove(key) {\r\n storage.removeItem(key);\r\n },\r\n\r\n /**\r\n * Clear all items\r\n */\r\n clear() {\r\n storage.clear();\r\n },\r\n };\r\n};\r\n\r\nexport const local = createStorage(\"localStorage\");\r\nexport const session = createStorage(\"sessionStorage\");\r\n","/**\r\n * State Management\r\n * A tiny reactive store (inspired by Svelte stores).\r\n */\r\n\r\n/**\r\n * Creates a reactive store\r\n * @param {any} initialValue\r\n * @returns {Object}\r\n */\r\nexport const createStore = (initialValue) => {\r\n let value = initialValue;\r\n const subscribers = new Set();\r\n\r\n /**\r\n * Subscribe to changes\r\n * @param {Function} fn\r\n * @returns {Function} Unsubscribe function\r\n */\r\n const subscribe = (fn) => {\r\n subscribers.add(fn);\r\n fn(value);\r\n return () => subscribers.delete(fn);\r\n };\r\n\r\n /**\r\n * Update value and notify subscribers\r\n * @param {any|Function} newValue\r\n */\r\n const update = (newValue) => {\r\n if (typeof newValue === \"function\") {\r\n value = newValue(value);\r\n } else {\r\n value = newValue;\r\n }\r\n subscribers.forEach((fn) => fn(value));\r\n };\r\n\r\n /**\r\n * Get current value\r\n * @returns {any}\r\n */\r\n const get = () => value;\r\n\r\n return { subscribe, update, get };\r\n};\r\n","/**\r\n * General Utilities\r\n * Common helper functions.\r\n */\r\n\r\n/**\r\n * Debounce function\r\n * @param {Function} fn\r\n * @param {number} delay\r\n * @returns {Function}\r\n */\r\nexport const debounce = (fn, delay = 300) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => fn.apply(this, args), delay);\r\n };\r\n};\r\n\r\n/**\r\n * Throttle function\r\n * @param {Function} fn\r\n * @param {number} limit\r\n * @returns {Function}\r\n */\r\nexport const throttle = (fn, limit = 300) => {\r\n let lastFunc;\r\n let lastRan;\r\n return (...args) => {\r\n if (!lastRan) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n } else {\r\n clearTimeout(lastFunc);\r\n lastFunc = setTimeout(\r\n () => {\r\n if (Date.now() - lastRan >= limit) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n }\r\n },\r\n limit - (Date.now() - lastRan),\r\n );\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Deep clone an object\r\n * @param {any} obj\r\n * @returns {any}\r\n */\r\nexport const deepClone = (obj) => {\r\n if (obj === null || typeof obj !== \"object\") return obj;\r\n return JSON.parse(JSON.stringify(obj));\r\n};\r\n\r\n/**\r\n * Generates a simple UUID-like string\r\n * @returns {string}\r\n */\r\nexport const uuid = () => {\r\n return (\r\n Math.random().toString(36).substring(2, 10) +\r\n Date.now().toString(36).substring(2, 6)\r\n );\r\n};\r\n","/**\r\n * Date Utilities\r\n * Simple and efficient date formatting and manipulation.\r\n */\r\n\r\n/**\r\n * Basic Date Formatter\r\n * @param {Date|string|number} date\r\n * @param {string} pattern - Default: 'YYYY-MM-DD'\r\n * @returns {string}\r\n */\r\nexport const formatDate = (date, pattern = \"YYYY-MM-DD\") => {\r\n const d = new Date(date);\r\n if (isNaN(d.getTime())) return \"Invalid Date\";\r\n\r\n const map = {\r\n YYYY: d.getFullYear(),\r\n MM: String(d.getMonth() + 1).padStart(2, \"0\"),\r\n DD: String(d.getDate()).padStart(2, \"0\"),\r\n HH: String(d.getHours()).padStart(2, \"0\"),\r\n mm: String(d.getMinutes()).padStart(2, \"0\"),\r\n ss: String(d.getSeconds()).padStart(2, \"0\"),\r\n };\r\n\r\n return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);\r\n};\r\n\r\n/**\r\n * Returns a human-readable relative time (e.g., \"5 minutes ago\")\r\n * @param {Date|string|number} date\r\n * @returns {string}\r\n */\r\nexport const relativeTime = (date) => {\r\n const d = new Date(date);\r\n const now = new Date();\r\n const diff = Math.floor((now - d) / 1000);\r\n\r\n if (diff < 60) return \"just now\";\r\n if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;\r\n if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;\r\n if (diff < 2592000) return `${Math.floor(diff / 86400)} days ago`;\r\n\r\n return formatDate(d);\r\n};\r\n\r\n/**\r\n * Add days to a date\r\n * @param {Date|string|number} date\r\n * @param {number} days\r\n * @returns {Date}\r\n */\r\nexport const addDays = (date, days) => {\r\n const d = new Date(date);\r\n d.setDate(d.getDate() + days);\r\n return d;\r\n};\r\n\r\n/**\r\n * Check if two dates are the same day\r\n * @param {Date} d1\r\n * @param {Date} d2\r\n * @returns {boolean}\r\n */\r\nexport const isSameDay = (d1, d2) => {\r\n return (\r\n d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n );\r\n};\r\n","/**\r\n * Formatting Utilities\r\n * Tools for number, currency, and string formatting.\r\n */\r\n\r\n/**\r\n * Currency Formatter\r\n * @param {number} amount\r\n * @param {string} locale - Default: 'id-ID'\r\n * @param {string} currency - Default: 'IDR'\r\n * @returns {string}\r\n */\r\nexport const currency = (amount, locale = \"id-ID\", currency = \"IDR\") => {\r\n return new Intl.NumberFormat(locale, {\r\n style: \"currency\",\r\n currency: currency,\r\n }).format(amount);\r\n};\r\n\r\n/**\r\n * Number Formatter with decimals\r\n * @param {number} n\r\n * @param {number} decimals - Default: 0\r\n * @returns {string}\r\n */\r\nexport const number = (n, decimals = 0) => {\r\n return new Intl.NumberFormat(\"id-ID\", {\r\n minimumFractionDigits: decimals,\r\n maximumFractionDigits: decimals,\r\n }).format(n);\r\n};\r\n\r\n/**\r\n * Truncate string with ellipsis\r\n * @param {string} str\r\n * @param {number} length - Default: 30\r\n * @returns {string}\r\n */\r\nexport const truncate = (str, length = 30) => {\r\n if (!str) return \"\";\r\n return str.length > length ? str.substring(0, length) + \"...\" : str;\r\n};\r\n\r\n/**\r\n * Convert string to slug (URL friendly)\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const slugify = (str) => {\r\n if (!str) return \"\";\r\n return str\r\n .toLowerCase()\r\n .trim()\r\n .replace(/[^\\w\\s-]/g, \"\")\r\n .replace(/[\\s_-]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n};\r\n\r\n/**\r\n * Capitalize first letter of each word\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const capitalize = (str) => {\r\n if (!str) return \"\";\r\n return str.replace(/\\b\\w/g, (l) => l.toUpperCase());\r\n};\r\n","/**\r\n * Validation Utilities\r\n * Common regex-based validation helpers.\r\n */\r\n\r\n/**\r\n * Check if string is a valid email\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmail = (str) => {\r\n const re = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n return re.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is a valid URL\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isURL = (str) => {\r\n try {\r\n new URL(str);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Check if string contains only numbers\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isNumeric = (str) => {\r\n return /^\\d+$/.test(str);\r\n};\r\n\r\n/**\r\n * Check for strong password\r\n * (Min 8 chars, 1 uppercase, 1 lowercase, 1 number)\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isStrongPassword = (str) => {\r\n return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is empty or only whitespace\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmpty = (str) => {\r\n return !str || str.trim().length === 0;\r\n};\r\n"],"names":["this"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const t=(t,e=document)=>e.querySelector(t),e=(t,e=document)=>Array.from(e.querySelectorAll(t)),r=(t,e={})=>{const r=document.createElement(t),{attr:o={},style:n={},text:a="",html:s="",children:c=[]}=e;return Object.entries(o).forEach(([t,e])=>r.setAttribute(t,e)),Object.assign(r.style,n),a&&(r.textContent=a),s&&(r.innerHTML=s),c.forEach(t=>{t instanceof HTMLElement?r.appendChild(t):r.append(t)}),r},o=(t,e,r,o)=>{t.addEventListener(e,e=>{const n=e.target.closest(r);n&&t.contains(n)&&o.call(n,e,n)})},n=async(t,e={})=>{const{method:r="GET",headers:o={},body:n=null,interceptors:a={request:[],response:[]}}=e;let s={method:r,headers:{"Content-Type":"application/json",...o}};n&&"object"==typeof n?s.body=JSON.stringify(n):n&&(s.body=n),a.request.forEach(t=>{s=t(s)||s});try{const e=await fetch(t,s);let r=await e.json().catch(()=>null);if(a.response.forEach(t=>{r=t(r,e)||r}),!e.ok)throw{status:e.status,data:r};return r}catch(t){throw console.error("Fetch Error:",t),t}},a={get:(t,e)=>n(t,{...e,method:"GET"}),post:(t,e,r)=>n(t,{...r,method:"POST",body:e}),put:(t,e,r)=>n(t,{...r,method:"PUT",body:e}),delete:(t,e)=>n(t,{...e,method:"DELETE"})},s=(t="localStorage")=>{const e=window[t];return{set(t,r){try{const o=JSON.stringify(r);e.setItem(t,o)}catch(e){console.error(`Storage Error (set): ${t}`,e)}},get(t,r=null){try{const o=e.getItem(t);return o?JSON.parse(o):r}catch(e){return console.error(`Storage Error (get): ${t}`,e),r}},remove(t){e.removeItem(t)},clear(){e.clear()}}},c=s("localStorage"),l=s("sessionStorage"),i=t=>{let e=t;const r=new Set;return{subscribe:t=>(r.add(t),t(e),()=>r.delete(t)),update:t=>{e="function"==typeof t?t(e):t,r.forEach(t=>t(e))},get:()=>e}},u=(t,e=300)=>{let r;return(...o)=>{clearTimeout(r),r=setTimeout(()=>t.apply(void 0,o),e)}},g=(t,e=300)=>{let r,o;return(...n)=>{o?(clearTimeout(r),r=setTimeout(()=>{Date.now()-o>=e&&(t.apply(void 0,n),o=Date.now())},e-(Date.now()-o))):(t.apply(void 0,n),o=Date.now())}},d=t=>null===t||"object"!=typeof t?t:JSON.parse(JSON.stringify(t)),m=()=>Math.random().toString(36).substring(2,10)+Date.now().toString(36).substring(2,6),p=(t,e="YYYY-MM-DD")=>{const r=new Date(t);if(isNaN(r.getTime()))return"Invalid Date";const o={YYYY:r.getFullYear(),MM:String(r.getMonth()+1).padStart(2,"0"),DD:String(r.getDate()).padStart(2,"0"),HH:String(r.getHours()).padStart(2,"0"),mm:String(r.getMinutes()).padStart(2,"0"),ss:String(r.getSeconds()).padStart(2,"0")};return e.replace(/YYYY|MM|DD|HH|mm|ss/g,t=>o[t])},h=t=>{const e=new Date(t),r=new Date,o=Math.floor((r-e)/1e3);return o<60?"just now":o<3600?`${Math.floor(o/60)} minutes ago`:o<86400?`${Math.floor(o/3600)} hours ago`:o<2592e3?`${Math.floor(o/86400)} days ago`:p(e)},y=(t,e)=>{const r=new Date(t);return r.setDate(r.getDate()+e),r},D=(t,e)=>t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()&&t.getDate()===e.getDate(),S=(t,e="id-ID",r="IDR")=>new Intl.NumberFormat(e,{style:"currency",currency:r}).format(t),f=(t,e=0)=>new Intl.NumberFormat("id-ID",{minimumFractionDigits:e,maximumFractionDigits:e}).format(t),w=(t,e=30)=>t?t.length>e?t.substring(0,e)+"...":t:"",b=t=>t?t.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_-]+/g,"-").replace(/^-+|-+$/g,""):"",M=t=>t?t.replace(/\b\w/g,t=>t.toUpperCase()):"",E=t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t),Y=t=>{try{return new URL(t),!0}catch{return!1}},T=t=>/^\d+$/.test(t),I=t=>/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(t),N=t=>!t||0===t.trim().length;export{t as $,e as $$,y as addDays,M as capitalize,r as create,i as createStore,S as currency,u as debounce,d as deepClone,p as formatDate,a as http,E as isEmail,N as isEmpty,T as isNumeric,D as isSameDay,I as isStrongPassword,Y as isURL,c as local,f as number,o as on,h as relativeTime,l as session,b as slugify,g as throttle,w as truncate,m as uuid};
|
|
2
|
+
//# sourceMappingURL=index.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.min.js","sources":["../src/dom.js","../src/http.js","../src/storage.js","../src/state.js","../src/utils.js","../src/date.js","../src/format.js","../src/validation.js"],"sourcesContent":["/**\r\n * DOM Utilities\r\n * Premium query selectors and manipulation tools.\r\n */\r\n\r\n/**\r\n * Higher performance querySelector wrapper\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement|null}\r\n */\r\nexport const $ = (selector, context = document) => {\r\n return context.querySelector(selector);\r\n};\r\n\r\n/**\r\n * querySelectorAll wrapper that returns an array instead of a NodeList\r\n * @param {string} selector\r\n * @param {HTMLElement|Document} context\r\n * @returns {HTMLElement[]}\r\n */\r\nexport const $$ = (selector, context = document) => {\r\n return Array.from(context.querySelectorAll(selector));\r\n};\r\n\r\n/**\r\n * Create element with attributes and styles\r\n * @param {string} tag\r\n * @param {Object} options\r\n * @returns {HTMLElement}\r\n */\r\nexport const create = (tag, options = {}) => {\r\n const el = document.createElement(tag);\r\n const {\r\n attr = {},\r\n style = {},\r\n text = \"\",\r\n html = \"\",\r\n children = [],\r\n } = options;\r\n\r\n Object.entries(attr).forEach(([k, v]) => el.setAttribute(k, v));\r\n Object.assign(el.style, style);\r\n\r\n if (text) el.textContent = text;\r\n if (html) el.innerHTML = html;\r\n\r\n children.forEach((child) => {\r\n if (child instanceof HTMLElement) el.appendChild(child);\r\n else el.append(child);\r\n });\r\n\r\n return el;\r\n};\r\n\r\n/**\r\n * Event delegation helper\r\n * @param {HTMLElement|Document} parent\r\n * @param {string} event\r\n * @param {string} selector\r\n * @param {Function} handler\r\n */\r\nexport const on = (parent, event, selector, handler) => {\r\n parent.addEventListener(event, (e) => {\r\n const target = e.target.closest(selector);\r\n if (target && parent.contains(target)) {\r\n handler.call(target, e, target);\r\n }\r\n });\r\n};\r\n","/**\r\n * HTTP Utilities\r\n * Clean Fetch API wrapper with easy JSON handling and interceptors.\r\n */\r\n\r\nconst request = async (url, options = {}) => {\r\n const {\r\n method = \"GET\",\r\n headers = {},\r\n body = null,\r\n interceptors = { request: [], response: [] },\r\n } = options;\r\n\r\n let config = {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n };\r\n\r\n if (body && typeof body === \"object\") {\r\n config.body = JSON.stringify(body);\r\n } else if (body) {\r\n config.body = body;\r\n }\r\n\r\n // Request Interceptors\r\n interceptors.request.forEach((fn) => {\r\n config = fn(config) || config;\r\n });\r\n\r\n try {\r\n const response = await fetch(url, config);\r\n let data = await response.json().catch(() => null);\r\n\r\n // Response Interceptors\r\n interceptors.response.forEach((fn) => {\r\n data = fn(data, response) || data;\r\n });\r\n\r\n if (!response.ok) {\r\n throw { status: response.status, data };\r\n }\r\n\r\n return data;\r\n } catch (error) {\r\n console.error(\"Fetch Error:\", error);\r\n throw error;\r\n }\r\n};\r\n\r\nexport const http = {\r\n get: (url, options) => request(url, { ...options, method: \"GET\" }),\r\n post: (url, body, options) =>\r\n request(url, { ...options, method: \"POST\", body }),\r\n put: (url, body, options) =>\r\n request(url, { ...options, method: \"PUT\", body }),\r\n delete: (url, options) => request(url, { ...options, method: \"DELETE\" }),\r\n};\r\n","/**\r\n * Storage Utilities\r\n * Type-safe and auto-serialized local/session storage.\r\n */\r\n\r\nconst createStorage = (type = \"localStorage\") => {\r\n const storage = window[type];\r\n\r\n return {\r\n /**\r\n * Set item with auto-serialization\r\n * @param {string} key\r\n * @param {any} value\r\n */\r\n set(key, value) {\r\n try {\r\n const serialized = JSON.stringify(value);\r\n storage.setItem(key, serialized);\r\n } catch (e) {\r\n console.error(`Storage Error (set): ${key}`, e);\r\n }\r\n },\r\n\r\n /**\r\n * Get item with auto-deserialization\r\n * @param {string} key\r\n * @param {any} fallback\r\n * @returns {any}\r\n */\r\n get(key, fallback = null) {\r\n try {\r\n const item = storage.getItem(key);\r\n return item ? JSON.parse(item) : fallback;\r\n } catch (e) {\r\n console.error(`Storage Error (get): ${key}`, e);\r\n return fallback;\r\n }\r\n },\r\n\r\n /**\r\n * Remove item\r\n * @param {string} key\r\n */\r\n remove(key) {\r\n storage.removeItem(key);\r\n },\r\n\r\n /**\r\n * Clear all items\r\n */\r\n clear() {\r\n storage.clear();\r\n },\r\n };\r\n};\r\n\r\nexport const local = createStorage(\"localStorage\");\r\nexport const session = createStorage(\"sessionStorage\");\r\n","/**\r\n * State Management\r\n * A tiny reactive store (inspired by Svelte stores).\r\n */\r\n\r\n/**\r\n * Creates a reactive store\r\n * @param {any} initialValue\r\n * @returns {Object}\r\n */\r\nexport const createStore = (initialValue) => {\r\n let value = initialValue;\r\n const subscribers = new Set();\r\n\r\n /**\r\n * Subscribe to changes\r\n * @param {Function} fn\r\n * @returns {Function} Unsubscribe function\r\n */\r\n const subscribe = (fn) => {\r\n subscribers.add(fn);\r\n fn(value);\r\n return () => subscribers.delete(fn);\r\n };\r\n\r\n /**\r\n * Update value and notify subscribers\r\n * @param {any|Function} newValue\r\n */\r\n const update = (newValue) => {\r\n if (typeof newValue === \"function\") {\r\n value = newValue(value);\r\n } else {\r\n value = newValue;\r\n }\r\n subscribers.forEach((fn) => fn(value));\r\n };\r\n\r\n /**\r\n * Get current value\r\n * @returns {any}\r\n */\r\n const get = () => value;\r\n\r\n return { subscribe, update, get };\r\n};\r\n","/**\r\n * General Utilities\r\n * Common helper functions.\r\n */\r\n\r\n/**\r\n * Debounce function\r\n * @param {Function} fn\r\n * @param {number} delay\r\n * @returns {Function}\r\n */\r\nexport const debounce = (fn, delay = 300) => {\r\n let timeout;\r\n return (...args) => {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => fn.apply(this, args), delay);\r\n };\r\n};\r\n\r\n/**\r\n * Throttle function\r\n * @param {Function} fn\r\n * @param {number} limit\r\n * @returns {Function}\r\n */\r\nexport const throttle = (fn, limit = 300) => {\r\n let lastFunc;\r\n let lastRan;\r\n return (...args) => {\r\n if (!lastRan) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n } else {\r\n clearTimeout(lastFunc);\r\n lastFunc = setTimeout(\r\n () => {\r\n if (Date.now() - lastRan >= limit) {\r\n fn.apply(this, args);\r\n lastRan = Date.now();\r\n }\r\n },\r\n limit - (Date.now() - lastRan),\r\n );\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Deep clone an object\r\n * @param {any} obj\r\n * @returns {any}\r\n */\r\nexport const deepClone = (obj) => {\r\n if (obj === null || typeof obj !== \"object\") return obj;\r\n return JSON.parse(JSON.stringify(obj));\r\n};\r\n\r\n/**\r\n * Generates a simple UUID-like string\r\n * @returns {string}\r\n */\r\nexport const uuid = () => {\r\n return (\r\n Math.random().toString(36).substring(2, 10) +\r\n Date.now().toString(36).substring(2, 6)\r\n );\r\n};\r\n","/**\r\n * Date Utilities\r\n * Simple and efficient date formatting and manipulation.\r\n */\r\n\r\n/**\r\n * Basic Date Formatter\r\n * @param {Date|string|number} date\r\n * @param {string} pattern - Default: 'YYYY-MM-DD'\r\n * @returns {string}\r\n */\r\nexport const formatDate = (date, pattern = \"YYYY-MM-DD\") => {\r\n const d = new Date(date);\r\n if (isNaN(d.getTime())) return \"Invalid Date\";\r\n\r\n const map = {\r\n YYYY: d.getFullYear(),\r\n MM: String(d.getMonth() + 1).padStart(2, \"0\"),\r\n DD: String(d.getDate()).padStart(2, \"0\"),\r\n HH: String(d.getHours()).padStart(2, \"0\"),\r\n mm: String(d.getMinutes()).padStart(2, \"0\"),\r\n ss: String(d.getSeconds()).padStart(2, \"0\"),\r\n };\r\n\r\n return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);\r\n};\r\n\r\n/**\r\n * Returns a human-readable relative time (e.g., \"5 minutes ago\")\r\n * @param {Date|string|number} date\r\n * @returns {string}\r\n */\r\nexport const relativeTime = (date) => {\r\n const d = new Date(date);\r\n const now = new Date();\r\n const diff = Math.floor((now - d) / 1000);\r\n\r\n if (diff < 60) return \"just now\";\r\n if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;\r\n if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;\r\n if (diff < 2592000) return `${Math.floor(diff / 86400)} days ago`;\r\n\r\n return formatDate(d);\r\n};\r\n\r\n/**\r\n * Add days to a date\r\n * @param {Date|string|number} date\r\n * @param {number} days\r\n * @returns {Date}\r\n */\r\nexport const addDays = (date, days) => {\r\n const d = new Date(date);\r\n d.setDate(d.getDate() + days);\r\n return d;\r\n};\r\n\r\n/**\r\n * Check if two dates are the same day\r\n * @param {Date} d1\r\n * @param {Date} d2\r\n * @returns {boolean}\r\n */\r\nexport const isSameDay = (d1, d2) => {\r\n return (\r\n d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n );\r\n};\r\n","/**\r\n * Formatting Utilities\r\n * Tools for number, currency, and string formatting.\r\n */\r\n\r\n/**\r\n * Currency Formatter\r\n * @param {number} amount\r\n * @param {string} locale - Default: 'id-ID'\r\n * @param {string} currency - Default: 'IDR'\r\n * @returns {string}\r\n */\r\nexport const currency = (amount, locale = \"id-ID\", currency = \"IDR\") => {\r\n return new Intl.NumberFormat(locale, {\r\n style: \"currency\",\r\n currency: currency,\r\n }).format(amount);\r\n};\r\n\r\n/**\r\n * Number Formatter with decimals\r\n * @param {number} n\r\n * @param {number} decimals - Default: 0\r\n * @returns {string}\r\n */\r\nexport const number = (n, decimals = 0) => {\r\n return new Intl.NumberFormat(\"id-ID\", {\r\n minimumFractionDigits: decimals,\r\n maximumFractionDigits: decimals,\r\n }).format(n);\r\n};\r\n\r\n/**\r\n * Truncate string with ellipsis\r\n * @param {string} str\r\n * @param {number} length - Default: 30\r\n * @returns {string}\r\n */\r\nexport const truncate = (str, length = 30) => {\r\n if (!str) return \"\";\r\n return str.length > length ? str.substring(0, length) + \"...\" : str;\r\n};\r\n\r\n/**\r\n * Convert string to slug (URL friendly)\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const slugify = (str) => {\r\n if (!str) return \"\";\r\n return str\r\n .toLowerCase()\r\n .trim()\r\n .replace(/[^\\w\\s-]/g, \"\")\r\n .replace(/[\\s_-]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n};\r\n\r\n/**\r\n * Capitalize first letter of each word\r\n * @param {string} str\r\n * @returns {string}\r\n */\r\nexport const capitalize = (str) => {\r\n if (!str) return \"\";\r\n return str.replace(/\\b\\w/g, (l) => l.toUpperCase());\r\n};\r\n","/**\r\n * Validation Utilities\r\n * Common regex-based validation helpers.\r\n */\r\n\r\n/**\r\n * Check if string is a valid email\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmail = (str) => {\r\n const re = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n return re.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is a valid URL\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isURL = (str) => {\r\n try {\r\n new URL(str);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Check if string contains only numbers\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isNumeric = (str) => {\r\n return /^\\d+$/.test(str);\r\n};\r\n\r\n/**\r\n * Check for strong password\r\n * (Min 8 chars, 1 uppercase, 1 lowercase, 1 number)\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isStrongPassword = (str) => {\r\n return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/.test(str);\r\n};\r\n\r\n/**\r\n * Check if string is empty or only whitespace\r\n * @param {string} str\r\n * @returns {boolean}\r\n */\r\nexport const isEmpty = (str) => {\r\n return !str || str.trim().length === 0;\r\n};\r\n"],"names":["$","selector","context","document","querySelector","$$","Array","from","querySelectorAll","create","tag","options","el","createElement","attr","style","text","html","children","Object","entries","forEach","k","v","setAttribute","assign","textContent","innerHTML","child","HTMLElement","appendChild","append","on","parent","event","handler","addEventListener","e","target","closest","contains","call","request","async","url","method","headers","body","interceptors","response","config","JSON","stringify","fn","fetch","data","json","catch","ok","status","error","console","http","get","post","put","delete","createStorage","type","storage","window","set","key","value","serialized","setItem","fallback","item","getItem","parse","remove","removeItem","clear","local","session","createStore","initialValue","subscribers","Set","subscribe","add","update","newValue","debounce","delay","timeout","args","clearTimeout","setTimeout","apply","this","throttle","limit","lastFunc","lastRan","Date","now","deepClone","obj","uuid","Math","random","toString","substring","formatDate","date","pattern","d","isNaN","getTime","map","YYYY","getFullYear","MM","String","getMonth","padStart","DD","getDate","HH","getHours","mm","getMinutes","ss","getSeconds","replace","matched","relativeTime","diff","floor","addDays","days","setDate","isSameDay","d1","d2","currency","amount","locale","Intl","NumberFormat","format","number","n","decimals","minimumFractionDigits","maximumFractionDigits","truncate","str","length","slugify","toLowerCase","trim","capitalize","l","toUpperCase","isEmail","test","isURL","URL","isNumeric","isStrongPassword","isEmpty"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myusufazmi/ultimate-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Modern JS utility library for high-performance projects",
|
|
5
|
-
"main": "
|
|
6
|
-
"module": "
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"files": [
|
|
9
|
+
"dist",
|
|
9
10
|
"src",
|
|
10
11
|
"README.md",
|
|
11
12
|
"LICENSE"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
15
|
-
"serve": "npx -y lite-server"
|
|
16
|
+
"serve": "npx -y lite-server",
|
|
17
|
+
"build": "rollup -c"
|
|
16
18
|
},
|
|
17
19
|
"keywords": [
|
|
18
20
|
"javascript",
|
|
@@ -31,5 +33,11 @@
|
|
|
31
33
|
"bugs": {
|
|
32
34
|
"url": "https://github.com/yourusername/ultimate-tools/issues"
|
|
33
35
|
},
|
|
34
|
-
"homepage": "https://github.com/yourusername/ultimate-tools#readme"
|
|
36
|
+
"homepage": "https://github.com/yourusername/ultimate-tools#readme",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
39
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
40
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
41
|
+
"rollup": "^4.57.1"
|
|
42
|
+
}
|
|
35
43
|
}
|