elementdrawing 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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/elementdrawing.min.js +3 -0
  3. package/dist/elementdrawing.min.js.LICENSE.txt +8 -0
  4. package/dist/elementdrawing.min.js.map +1 -0
  5. package/dist/index.html +1 -0
  6. package/package.json +127 -0
  7. package/src/core/bridge.h +855 -0
  8. package/src/core/diff.c +900 -0
  9. package/src/core/element.c +1078 -0
  10. package/src/core/event.c +813 -0
  11. package/src/core/fiber.c +1027 -0
  12. package/src/core/hooks.c +919 -0
  13. package/src/core/renderer.c +963 -0
  14. package/src/core/scheduler.c +702 -0
  15. package/src/core/state.c +803 -0
  16. package/src/css/animations.css +779 -0
  17. package/src/css/base.css +615 -0
  18. package/src/css/components.css +1311 -0
  19. package/src/css/tailwind.css +370 -0
  20. package/src/css/themes.css +517 -0
  21. package/src/css/utilities.css +475 -0
  22. package/src/index.js +746 -0
  23. package/src/js/animation.js +655 -0
  24. package/src/js/dom.js +665 -0
  25. package/src/js/events.js +585 -0
  26. package/src/js/http.js +446 -0
  27. package/src/js/index.js +26 -0
  28. package/src/js/router.js +483 -0
  29. package/src/js/store.js +539 -0
  30. package/src/js/utils.js +593 -0
  31. package/src/js/validator.js +529 -0
  32. package/src/jsx/components/Accordion.jsx +210 -0
  33. package/src/jsx/components/Alert.jsx +169 -0
  34. package/src/jsx/components/Avatar.jsx +214 -0
  35. package/src/jsx/components/Badge.jsx +136 -0
  36. package/src/jsx/components/Breadcrumb.jsx +200 -0
  37. package/src/jsx/components/Button.jsx +188 -0
  38. package/src/jsx/components/Card.jsx +192 -0
  39. package/src/jsx/components/Carousel.jsx +278 -0
  40. package/src/jsx/components/Checkbox.jsx +215 -0
  41. package/src/jsx/components/Dialog.jsx +242 -0
  42. package/src/jsx/components/Drawer.jsx +190 -0
  43. package/src/jsx/components/Dropdown.jsx +268 -0
  44. package/src/jsx/components/Form.jsx +274 -0
  45. package/src/jsx/components/Input.jsx +285 -0
  46. package/src/jsx/components/Menu.jsx +276 -0
  47. package/src/jsx/components/Modal.jsx +274 -0
  48. package/src/jsx/components/Navbar.jsx +292 -0
  49. package/src/jsx/components/Pagination.jsx +268 -0
  50. package/src/jsx/components/Progress.jsx +252 -0
  51. package/src/jsx/components/Radio.jsx +208 -0
  52. package/src/jsx/components/Select.jsx +397 -0
  53. package/src/jsx/components/Sidebar.jsx +250 -0
  54. package/src/jsx/components/Slider.jsx +310 -0
  55. package/src/jsx/components/Spinner.jsx +198 -0
  56. package/src/jsx/components/Switch.jsx +201 -0
  57. package/src/jsx/components/Table.jsx +332 -0
  58. package/src/jsx/components/Tabs.jsx +227 -0
  59. package/src/jsx/components/Textarea.jsx +212 -0
  60. package/src/jsx/components/Toast.jsx +270 -0
  61. package/src/jsx/components/Tooltip.jsx +178 -0
  62. package/src/jsx/components/Typography.jsx +299 -0
  63. package/src/jsx/components/index.jsx +70 -0
  64. package/src/jsx/core/element.js +3 -0
  65. package/src/jsx/hooks/index.js +356 -0
  66. package/src/jsx/hooks/useCallback.js +472 -0
  67. package/src/jsx/hooks/useContext.js +586 -0
  68. package/src/jsx/hooks/useEffect.js +704 -0
  69. package/src/jsx/hooks/useLayoutEffect.js +508 -0
  70. package/src/jsx/hooks/useMemo.js +689 -0
  71. package/src/jsx/hooks/useReducer.js +729 -0
  72. package/src/jsx/hooks/useRef.js +542 -0
  73. package/src/jsx/hooks/useState.js +854 -0
  74. package/src/jsx/runtime/commit.js +903 -0
  75. package/src/jsx/runtime/createElement.js +860 -0
  76. package/src/jsx/runtime/index.js +356 -0
  77. package/src/jsx/runtime/reconcile.js +687 -0
  78. package/src/jsx/runtime/render.js +914 -0
package/src/js/http.js ADDED
@@ -0,0 +1,446 @@
1
+ /**
2
+ * HTTP Client
3
+ * ElementDrawing Framework - Full-featured HTTP client with methods,
4
+ * interceptors, cancellation, retry, timeout, progress, and caching.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ // ─── Configuration ────────────────────────────────────────────────────────────
10
+
11
+ const defaultConfig = {
12
+ baseURL: '',
13
+ timeout: 30000,
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ 'Accept': 'application/json',
17
+ },
18
+ withCredentials: false,
19
+ responseType: 'json',
20
+ maxRetries: 0,
21
+ retryDelay: 1000,
22
+ retryBackoff: 2,
23
+ cache: false,
24
+ deduplicate: true,
25
+ };
26
+
27
+ // ─── Interceptor System ───────────────────────────────────────────────────────
28
+
29
+ function createInterceptorManager() {
30
+ const requestInterceptors = [];
31
+ const responseInterceptors = [];
32
+
33
+ return {
34
+ useRequest: function (fulfilled, rejected) {
35
+ requestInterceptors.push({ fulfilled, rejected });
36
+ return requestInterceptors.length - 1;
37
+ },
38
+ useResponse: function (fulfilled, rejected) {
39
+ responseInterceptors.push({ fulfilled, rejected });
40
+ return responseInterceptors.length - 1;
41
+ },
42
+ ejectRequest: function (id) { requestInterceptors[id] = null; },
43
+ ejectResponse: function (id) { responseInterceptors[id] = null; },
44
+ requestInterceptors,
45
+ responseInterceptors,
46
+ };
47
+ }
48
+
49
+ async function applyRequestInterceptors(config, interceptors) {
50
+ let result = config;
51
+ for (const interceptor of interceptors.requestInterceptors) {
52
+ if (!interceptor) continue;
53
+ try {
54
+ result = interceptor.fulfilled ? await interceptor.fulfilled(result) : result;
55
+ } catch (error) {
56
+ if (interceptor.rejected) { interceptor.rejected(error); }
57
+ throw error;
58
+ }
59
+ }
60
+ return result;
61
+ }
62
+
63
+ async function applyResponseInterceptors(response, interceptors) {
64
+ let result = response;
65
+ for (const interceptor of interceptors.responseInterceptors) {
66
+ if (!interceptor) continue;
67
+ try {
68
+ result = interceptor.fulfilled ? await interceptor.fulfilled(result) : result;
69
+ } catch (error) {
70
+ if (interceptor.rejected) { result = interceptor.rejected(error); }
71
+ }
72
+ }
73
+ return result;
74
+ }
75
+
76
+ // ─── Request Deduplication ────────────────────────────────────────────────────
77
+
78
+ const pendingRequests = new Map();
79
+
80
+ function generateRequestKey(config) {
81
+ return (config.method || 'GET') + ':' + config.url + ':' + JSON.stringify(config.params || {});
82
+ }
83
+
84
+ function deduplicateRequest(key, requestFn) {
85
+ if (pendingRequests.has(key)) return pendingRequests.get(key);
86
+ const promise = requestFn().finally(() => pendingRequests.delete(key));
87
+ pendingRequests.set(key, promise);
88
+ return promise;
89
+ }
90
+
91
+ // ─── HTTP Client Class ────────────────────────────────────────────────────────
92
+
93
+ function HttpClient(config) {
94
+ this.config = Object.assign({}, defaultConfig, config);
95
+ this.interceptors = createInterceptorManager();
96
+ this._authToken = null;
97
+ this._authHeader = 'Authorization';
98
+ this._authPrefix = 'Bearer';
99
+ }
100
+
101
+ /**
102
+ * Set authentication token.
103
+ * @param {string} token
104
+ * @param {string} [header='Authorization']
105
+ * @param {string} [prefix='Bearer']
106
+ */
107
+ HttpClient.prototype.setAuthToken = function (token, header, prefix) {
108
+ this._authToken = token;
109
+ this._authHeader = header || 'Authorization';
110
+ this._authPrefix = prefix || 'Bearer';
111
+ };
112
+
113
+ /**
114
+ * Remove authentication token.
115
+ */
116
+ HttpClient.prototype.clearAuthToken = function () {
117
+ this._authToken = null;
118
+ };
119
+
120
+ /**
121
+ * Build full URL from base URL, path, and params.
122
+ */
123
+ HttpClient.prototype._buildURL = function (url, params) {
124
+ let fullURL = this.config.baseURL + url;
125
+
126
+ if (params) {
127
+ const searchParams = new URLSearchParams();
128
+ Object.keys(params).forEach((key) => {
129
+ if (params[key] !== null && params[key] !== undefined) {
130
+ searchParams.append(key, params[key]);
131
+ }
132
+ });
133
+ const qs = searchParams.toString();
134
+ if (qs) fullURL += (fullURL.includes('?') ? '&' : '?') + qs;
135
+ }
136
+
137
+ return fullURL;
138
+ };
139
+
140
+ /**
141
+ * Build request headers.
142
+ */
143
+ HttpClient.prototype._buildHeaders = function (headers) {
144
+ const result = Object.assign({}, this.config.headers, headers);
145
+
146
+ if (this._authToken) {
147
+ result[this._authHeader] = this._authPrefix + ' ' + this._authToken;
148
+ }
149
+
150
+ return result;
151
+ };
152
+
153
+ /**
154
+ * Execute a request with retry logic.
155
+ */
156
+ HttpClient.prototype._request = function (config) {
157
+ const self = this;
158
+ const maxRetries = config.maxRetries !== undefined ? config.maxRetries : this.config.maxRetries;
159
+ const retryDelay = config.retryDelay !== undefined ? config.retryDelay : this.config.retryDelay;
160
+ const retryBackoff = config.retryBackoff !== undefined ? config.retryBackoff : this.config.retryBackoff;
161
+ let attempt = 0;
162
+
163
+ async function execute() {
164
+ attempt++;
165
+ const controller = new AbortController();
166
+ const timeoutId = config.timeout ? setTimeout(() => controller.abort(), config.timeout) : null;
167
+
168
+ if (config.signal) {
169
+ config.signal.addEventListener('abort', () => controller.abort());
170
+ }
171
+
172
+ const fetchConfig = {
173
+ method: config.method || 'GET',
174
+ headers: config.headers,
175
+ signal: controller.signal,
176
+ credentials: config.withCredentials ? 'include' : 'same-origin',
177
+ };
178
+
179
+ if (config.body !== undefined && config.body !== null) {
180
+ if (config.body instanceof FormData) {
181
+ fetchConfig.body = config.body;
182
+ delete fetchConfig.headers['Content-Type'];
183
+ } else if (typeof config.body === 'object') {
184
+ fetchConfig.body = JSON.stringify(config.body);
185
+ } else {
186
+ fetchConfig.body = config.body;
187
+ }
188
+ }
189
+
190
+ try {
191
+ const response = await fetch(config.url, fetchConfig);
192
+ if (timeoutId) clearTimeout(timeoutId);
193
+
194
+ if (!response.ok) {
195
+ const error = new Error('HTTP Error ' + response.status);
196
+ error.status = response.status;
197
+ error.statusText = response.statusText;
198
+ error.response = response;
199
+
200
+ // Retry on server errors
201
+ if (response.status >= 500 && attempt <= maxRetries) {
202
+ return retry();
203
+ }
204
+
205
+ throw error;
206
+ }
207
+
208
+ return await self._parseResponse(response, config.responseType);
209
+ } catch (error) {
210
+ if (timeoutId) clearTimeout(timeoutId);
211
+
212
+ if (error.name === 'AbortError') {
213
+ throw new Error('Request aborted' + (attempt <= maxRetries ? ' - will retry' : ''));
214
+ }
215
+
216
+ // Retry on network errors
217
+ if (attempt <= maxRetries) {
218
+ return retry();
219
+ }
220
+
221
+ throw error;
222
+ }
223
+ }
224
+
225
+ function retry() {
226
+ const delay = retryDelay * Math.pow(retryBackoff, attempt - 1);
227
+ return new Promise((resolve) => setTimeout(resolve, delay)).then(execute);
228
+ }
229
+
230
+ return execute();
231
+ };
232
+
233
+ /**
234
+ * Parse response based on response type.
235
+ */
236
+ HttpClient.prototype._parseResponse = async function (response, responseType) {
237
+ responseType = responseType || this.config.responseType;
238
+
239
+ switch (responseType) {
240
+ case 'json':
241
+ try { return await response.json(); }
242
+ catch (e) { return null; }
243
+ case 'text': return await response.text();
244
+ case 'blob': return await response.blob();
245
+ case 'arrayBuffer': return await response.arrayBuffer();
246
+ case 'formData': return await response.formData();
247
+ default: return await response.json();
248
+ }
249
+ };
250
+
251
+ /**
252
+ * Send an HTTP request.
253
+ * @param {Object} config
254
+ * @returns {Promise}
255
+ */
256
+ HttpClient.prototype.request = async function (config) {
257
+ config = Object.assign({}, this.config, config);
258
+ config.url = this._buildURL(config.url || '', config.params);
259
+ config.headers = this._buildHeaders(config.headers);
260
+
261
+ // Apply request interceptors
262
+ config = await applyRequestInterceptors(config, this.interceptors);
263
+
264
+ // Deduplicate GET requests
265
+ if (config.deduplicate !== false && this.config.deduplicate && (config.method || 'GET') === 'GET') {
266
+ const key = generateRequestKey(config);
267
+ const response = await deduplicateRequest(key, () => this._request(config));
268
+ return applyResponseInterceptors(response, this.interceptors);
269
+ }
270
+
271
+ const response = await this._request(config);
272
+ return applyResponseInterceptors(response, this.interceptors);
273
+ };
274
+
275
+ // ─── HTTP Methods ─────────────────────────────────────────────────────────────
276
+
277
+ /**
278
+ * GET request.
279
+ * @param {string} url
280
+ * @param {Object} [params]
281
+ * @param {Object} [config]
282
+ * @returns {Promise}
283
+ */
284
+ HttpClient.prototype.get = function (url, params, config) {
285
+ return this.request(Object.assign({ method: 'GET', url, params }, config));
286
+ };
287
+
288
+ /**
289
+ * POST request.
290
+ * @param {string} url
291
+ * @param {*} [data]
292
+ * @param {Object} [config]
293
+ * @returns {Promise}
294
+ */
295
+ HttpClient.prototype.post = function (url, data, config) {
296
+ return this.request(Object.assign({ method: 'POST', url, body: data }, config));
297
+ };
298
+
299
+ /**
300
+ * PUT request.
301
+ * @param {string} url
302
+ * @param {*} [data]
303
+ * @param {Object} [config]
304
+ * @returns {Promise}
305
+ */
306
+ HttpClient.prototype.put = function (url, data, config) {
307
+ return this.request(Object.assign({ method: 'PUT', url, body: data }, config));
308
+ };
309
+
310
+ /**
311
+ * PATCH request.
312
+ * @param {string} url
313
+ * @param {*} [data]
314
+ * @param {Object} [config]
315
+ * @returns {Promise}
316
+ */
317
+ HttpClient.prototype.patch = function (url, data, config) {
318
+ return this.request(Object.assign({ method: 'PATCH', url, body: data }, config));
319
+ };
320
+
321
+ /**
322
+ * DELETE request.
323
+ * @param {string} url
324
+ * @param {Object} [config]
325
+ * @returns {Promise}
326
+ */
327
+ HttpClient.prototype.delete = function (url, config) {
328
+ return this.request(Object.assign({ method: 'DELETE', url }, config));
329
+ };
330
+
331
+ /**
332
+ * HEAD request.
333
+ * @param {string} url
334
+ * @param {Object} [config]
335
+ * @returns {Promise}
336
+ */
337
+ HttpClient.prototype.head = function (url, config) {
338
+ return this.request(Object.assign({ method: 'HEAD', url }, config));
339
+ };
340
+
341
+ /**
342
+ * OPTIONS request.
343
+ * @param {string} url
344
+ * @param {Object} [config]
345
+ * @returns {Promise}
346
+ */
347
+ HttpClient.prototype.options = function (url, config) {
348
+ return this.request(Object.assign({ method: 'OPTIONS', url }, config));
349
+ };
350
+
351
+ /**
352
+ * Upload a file with progress tracking.
353
+ * @param {string} url
354
+ * @param {FormData} formData
355
+ * @param {Function} [onProgress]
356
+ * @param {Object} [config]
357
+ * @returns {Promise}
358
+ */
359
+ HttpClient.prototype.upload = function (url, formData, onProgress, config) {
360
+ return new Promise((resolve, reject) => {
361
+ const xhr = new XMLHttpRequest();
362
+ xhr.open('POST', this.config.baseURL + url);
363
+
364
+ const headers = this._buildHeaders(config && config.headers);
365
+ Object.keys(headers).forEach((key) => {
366
+ if (key !== 'Content-Type') xhr.setRequestHeader(key, headers[key]);
367
+ });
368
+
369
+ if (this._authToken) {
370
+ xhr.setRequestHeader(this._authHeader, this._authPrefix + ' ' + this._authToken);
371
+ }
372
+
373
+ if (onProgress) {
374
+ xhr.upload.onprogress = function (e) {
375
+ if (e.lengthComputable) {
376
+ onProgress({ loaded: e.loaded, total: e.total, progress: e.loaded / e.total });
377
+ }
378
+ };
379
+ }
380
+
381
+ xhr.onload = function () {
382
+ if (xhr.status >= 200 && xhr.status < 300) {
383
+ try { resolve(JSON.parse(xhr.responseText)); }
384
+ catch (e) { resolve(xhr.responseText); }
385
+ } else {
386
+ const error = new Error('Upload failed: ' + xhr.status);
387
+ error.status = xhr.status;
388
+ reject(error);
389
+ }
390
+ };
391
+
392
+ xhr.onerror = function () { reject(new Error('Upload network error')); };
393
+ xhr.ontimeout = function () { reject(new Error('Upload timeout')); };
394
+
395
+ if (config && config.signal) {
396
+ config.signal.addEventListener('abort', () => xhr.abort());
397
+ }
398
+
399
+ xhr.send(formData);
400
+ });
401
+ };
402
+
403
+ /**
404
+ * Download a file.
405
+ * @param {string} url
406
+ * @param {Object} [config]
407
+ * @returns {Promise<Blob>}
408
+ */
409
+ HttpClient.prototype.download = function (url, config) {
410
+ return this.request(Object.assign({ url, method: 'GET', responseType: 'blob' }, config));
411
+ };
412
+
413
+ // ─── Factory Function ─────────────────────────────────────────────────────────
414
+
415
+ /**
416
+ * Create a new HTTP client instance.
417
+ * @param {Object} [config]
418
+ * @returns {HttpClient}
419
+ */
420
+ function createHttpClient(config) {
421
+ return new HttpClient(config);
422
+ }
423
+
424
+ // Default instance
425
+ const http = new HttpClient();
426
+
427
+ // ─── Exports ──────────────────────────────────────────────────────────────────
428
+
429
+ module.exports = {
430
+ HttpClient,
431
+ createHttpClient,
432
+ http,
433
+ // Quick access methods on default instance
434
+ get: (url, params, config) => http.get(url, params, config),
435
+ post: (url, data, config) => http.post(url, data, config),
436
+ put: (url, data, config) => http.put(url, data, config),
437
+ patch: (url, data, config) => http.patch(url, data, config),
438
+ delete: (url, config) => http.delete(url, config),
439
+ head: (url, config) => http.head(url, config),
440
+ options: (url, config) => http.options(url, config),
441
+ upload: (url, formData, onProgress, config) => http.upload(url, formData, onProgress, config),
442
+ download: (url, config) => http.download(url, config),
443
+ setAuthToken: (token, header, prefix) => http.setAuthToken(token, header, prefix),
444
+ clearAuthToken: () => http.clearAuthToken(),
445
+ interceptors: http.interceptors,
446
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * JS Utilities Index
3
+ * ElementDrawing Framework - Re-exports all JS utility modules.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const dom = require('./dom');
9
+ const events = require('./events');
10
+ const utils = require('./utils');
11
+ const animation = require('./animation');
12
+ const http = require('./http');
13
+ const router = require('./router');
14
+ const store = require('./store');
15
+ const validator = require('./validator');
16
+
17
+ module.exports = {
18
+ dom,
19
+ events,
20
+ utils,
21
+ animation,
22
+ http,
23
+ router,
24
+ store,
25
+ validator,
26
+ };