@kaiserofthenight/human-js 1.0.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/README.md +545 -0
- package/examples/api-example/app.js +365 -0
- package/examples/counter/app.js +201 -0
- package/examples/todo-app/app.js +378 -0
- package/examples/user-dashboard/app.js +0 -0
- package/package.json +66 -0
- package/src/core/component.js +182 -0
- package/src/core/events.js +130 -0
- package/src/core/render.js +151 -0
- package/src/core/router.js +182 -0
- package/src/core/state.js +114 -0
- package/src/index.js +63 -0
- package/src/plugins/http.js +167 -0
- package/src/plugins/storage.js +181 -0
- package/src/plugins/validator.js +193 -0
- package/src/utils/dom.js +0 -0
- package/src/utils/helpers.js +209 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UTILITY HELPER FUNCTIONS
|
|
3
|
+
*
|
|
4
|
+
* Common utilities for everyday development.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generate unique ID
|
|
9
|
+
*/
|
|
10
|
+
export function uid(prefix = 'id') {
|
|
11
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Deep clone object
|
|
16
|
+
*/
|
|
17
|
+
export function clone(obj) {
|
|
18
|
+
return JSON.parse(JSON.stringify(obj));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Deep merge objects
|
|
23
|
+
*/
|
|
24
|
+
export function merge(...objects) {
|
|
25
|
+
return objects.reduce((result, obj) => {
|
|
26
|
+
Object.keys(obj).forEach(key => {
|
|
27
|
+
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
|
|
28
|
+
result[key] = merge(result[key] || {}, obj[key]);
|
|
29
|
+
} else {
|
|
30
|
+
result[key] = obj[key];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
}, {});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Format date
|
|
39
|
+
*/
|
|
40
|
+
export function formatDate(date, format = 'YYYY-MM-DD') {
|
|
41
|
+
const d = new Date(date);
|
|
42
|
+
const year = d.getFullYear();
|
|
43
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
44
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
45
|
+
const hours = String(d.getHours()).padStart(2, '0');
|
|
46
|
+
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
47
|
+
const seconds = String(d.getSeconds()).padStart(2, '0');
|
|
48
|
+
|
|
49
|
+
return format
|
|
50
|
+
.replace('YYYY', year)
|
|
51
|
+
.replace('MM', month)
|
|
52
|
+
.replace('DD', day)
|
|
53
|
+
.replace('HH', hours)
|
|
54
|
+
.replace('mm', minutes)
|
|
55
|
+
.replace('ss', seconds);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Sleep/delay
|
|
60
|
+
*/
|
|
61
|
+
export function sleep(ms) {
|
|
62
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Capitalize string
|
|
67
|
+
*/
|
|
68
|
+
export function capitalize(str) {
|
|
69
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Truncate string
|
|
74
|
+
*/
|
|
75
|
+
export function truncate(str, length = 50, suffix = '...') {
|
|
76
|
+
if (str.length <= length) return str;
|
|
77
|
+
return str.substring(0, length) + suffix;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Random number between min and max
|
|
82
|
+
*/
|
|
83
|
+
export function random(min, max) {
|
|
84
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Shuffle array
|
|
89
|
+
*/
|
|
90
|
+
export function shuffle(array) {
|
|
91
|
+
const copy = [...array];
|
|
92
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
93
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
94
|
+
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
95
|
+
}
|
|
96
|
+
return copy;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Group array by key
|
|
101
|
+
*/
|
|
102
|
+
export function groupBy(array, key) {
|
|
103
|
+
return array.reduce((result, item) => {
|
|
104
|
+
const group = typeof key === 'function' ? key(item) : item[key];
|
|
105
|
+
if (!result[group]) result[group] = [];
|
|
106
|
+
result[group].push(item);
|
|
107
|
+
return result;
|
|
108
|
+
}, {});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Unique array values
|
|
113
|
+
*/
|
|
114
|
+
export function unique(array) {
|
|
115
|
+
return [...new Set(array)];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if object is empty
|
|
120
|
+
*/
|
|
121
|
+
export function isEmpty(obj) {
|
|
122
|
+
if (obj === null || obj === undefined) return true;
|
|
123
|
+
if (Array.isArray(obj)) return obj.length === 0;
|
|
124
|
+
if (typeof obj === 'object') return Object.keys(obj).length === 0;
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get nested object property safely
|
|
130
|
+
*/
|
|
131
|
+
export function get(obj, path, defaultValue = undefined) {
|
|
132
|
+
const keys = path.split('.');
|
|
133
|
+
let result = obj;
|
|
134
|
+
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
if (result === null || result === undefined) {
|
|
137
|
+
return defaultValue;
|
|
138
|
+
}
|
|
139
|
+
result = result[key];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return result !== undefined ? result : defaultValue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Set nested object property
|
|
147
|
+
*/
|
|
148
|
+
export function set(obj, path, value) {
|
|
149
|
+
const keys = path.split('.');
|
|
150
|
+
const lastKey = keys.pop();
|
|
151
|
+
let current = obj;
|
|
152
|
+
|
|
153
|
+
for (const key of keys) {
|
|
154
|
+
if (!current[key] || typeof current[key] !== 'object') {
|
|
155
|
+
current[key] = {};
|
|
156
|
+
}
|
|
157
|
+
current = current[key];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
current[lastKey] = value;
|
|
161
|
+
return obj;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Pick properties from object
|
|
166
|
+
*/
|
|
167
|
+
export function pick(obj, keys) {
|
|
168
|
+
return keys.reduce((result, key) => {
|
|
169
|
+
if (key in obj) result[key] = obj[key];
|
|
170
|
+
return result;
|
|
171
|
+
}, {});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Omit properties from object
|
|
176
|
+
*/
|
|
177
|
+
export function omit(obj, keys) {
|
|
178
|
+
const result = { ...obj };
|
|
179
|
+
keys.forEach(key => delete result[key]);
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Wait for condition to be true
|
|
185
|
+
*/
|
|
186
|
+
export async function waitFor(condition, timeout = 5000) {
|
|
187
|
+
const startTime = Date.now();
|
|
188
|
+
|
|
189
|
+
while (!condition()) {
|
|
190
|
+
if (Date.now() - startTime > timeout) {
|
|
191
|
+
throw new Error('Timeout waiting for condition');
|
|
192
|
+
}
|
|
193
|
+
await sleep(100);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Retry function on failure
|
|
199
|
+
*/
|
|
200
|
+
export async function retry(fn, maxAttempts = 3, delay = 1000) {
|
|
201
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
202
|
+
try {
|
|
203
|
+
return await fn();
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (attempt === maxAttempts) throw error;
|
|
206
|
+
await sleep(delay);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|