@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.
@@ -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.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Modern JS utility library for high-performance projects",
5
- "main": "src/index.js",
6
- "module": "src/index.js",
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
  }