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/dom.js ADDED
@@ -0,0 +1,665 @@
1
+ /**
2
+ * DOM Manipulation Utilities
3
+ * ElementDrawing Framework - Comprehensive DOM querying, creation,
4
+ * manipulation, CSS, attributes, dimensions, visibility, and animation helpers.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ // ─── Query Selectors ──────────────────────────────────────────────────────────
10
+
11
+ /**
12
+ * Select a single element by ID.
13
+ * @param {string} id
14
+ * @param {Document|HTMLElement} [context=document]
15
+ * @returns {HTMLElement|null}
16
+ */
17
+ function byId(id, context) {
18
+ return (context || document).getElementById(id);
19
+ }
20
+
21
+ /**
22
+ * Select elements by class name.
23
+ * @param {string} className
24
+ * @param {Document|HTMLElement} [context=document]
25
+ * @returns {HTMLCollection}
26
+ */
27
+ function byClass(className, context) {
28
+ return (context || document).getElementsByClassName(className);
29
+ }
30
+
31
+ /**
32
+ * Select elements by tag name.
33
+ * @param {string} tagName
34
+ * @param {Document|HTMLElement} [context=document]
35
+ * @returns {HTMLCollection}
36
+ */
37
+ function byTag(tagName, context) {
38
+ return (context || document).getElementsByTagName(tagName);
39
+ }
40
+
41
+ /**
42
+ * Select the first element matching a CSS selector.
43
+ * @param {string} selector
44
+ * @param {Document|HTMLElement} [context=document]
45
+ * @returns {HTMLElement|null}
46
+ */
47
+ function query(selector, context) {
48
+ return (context || document).querySelector(selector);
49
+ }
50
+
51
+ /**
52
+ * Select all elements matching a CSS selector.
53
+ * @param {string} selector
54
+ * @param {Document|HTMLElement} [context=document]
55
+ * @returns {NodeList}
56
+ */
57
+ function queryAll(selector, context) {
58
+ return (context || document).querySelectorAll(selector);
59
+ }
60
+
61
+ // ─── DOM Creation ─────────────────────────────────────────────────────────────
62
+
63
+ /**
64
+ * Create an HTML element with optional attributes and children.
65
+ * @param {string} tagName
66
+ * @param {Object} [attrs]
67
+ * @param {...(string|HTMLElement)} children
68
+ * @returns {HTMLElement}
69
+ */
70
+ function createElement(tagName, attrs) {
71
+ const el = document.createElement(tagName);
72
+
73
+ if (attrs) {
74
+ Object.keys(attrs).forEach((key) => {
75
+ const value = attrs[key];
76
+ if (key === 'className' || key === 'class') {
77
+ el.className = value;
78
+ } else if (key === 'style' && typeof value === 'object') {
79
+ Object.assign(el.style, value);
80
+ } else if (key === 'style' && typeof value === 'string') {
81
+ el.style.cssText = value;
82
+ } else if (key.startsWith('data-')) {
83
+ el.setAttribute(key, value);
84
+ } else if (key.startsWith('on') && typeof value === 'function') {
85
+ const eventType = key.slice(2).toLowerCase();
86
+ el.addEventListener(eventType, value);
87
+ } else if (typeof value === 'boolean') {
88
+ if (value) el.setAttribute(key, '');
89
+ else el.removeAttribute(key);
90
+ } else {
91
+ el.setAttribute(key, value);
92
+ }
93
+ });
94
+ }
95
+
96
+ const childArgs = Array.prototype.slice.call(arguments, 2);
97
+ childArgs.forEach((child) => {
98
+ if (typeof child === 'string' || typeof child === 'number') {
99
+ el.appendChild(document.createTextNode(String(child)));
100
+ } else if (child instanceof HTMLElement || child instanceof DocumentFragment) {
101
+ el.appendChild(child);
102
+ }
103
+ });
104
+
105
+ return el;
106
+ }
107
+
108
+ /**
109
+ * Create a document fragment.
110
+ * @returns {DocumentFragment}
111
+ */
112
+ function createFragment() {
113
+ return document.createDocumentFragment();
114
+ }
115
+
116
+ /**
117
+ * Create a text node.
118
+ * @param {string} text
119
+ * @returns {Text}
120
+ */
121
+ function createTextNode(text) {
122
+ return document.createTextNode(text);
123
+ }
124
+
125
+ // ─── DOM Manipulation ─────────────────────────────────────────────────────────
126
+
127
+ /**
128
+ * Append a child to a parent element.
129
+ * @param {HTMLElement} parent
130
+ * @param {HTMLElement|DocumentFragment|string} child
131
+ * @returns {HTMLElement}
132
+ */
133
+ function append(parent, child) {
134
+ if (typeof child === 'string') {
135
+ parent.insertAdjacentHTML('beforeend', child);
136
+ } else {
137
+ parent.appendChild(child);
138
+ }
139
+ return parent;
140
+ }
141
+
142
+ /**
143
+ * Prepend a child to a parent element.
144
+ * @param {HTMLElement} parent
145
+ * @param {HTMLElement|DocumentFragment|string} child
146
+ * @returns {HTMLElement}
147
+ */
148
+ function prepend(parent, child) {
149
+ if (typeof child === 'string') {
150
+ parent.insertAdjacentHTML('afterbegin', child);
151
+ } else {
152
+ parent.insertBefore(child, parent.firstChild);
153
+ }
154
+ return parent;
155
+ }
156
+
157
+ /**
158
+ * Insert a node before a reference node.
159
+ * @param {HTMLElement} newNode
160
+ * @param {HTMLElement} referenceNode
161
+ * @returns {HTMLElement}
162
+ */
163
+ function insertBefore(newNode, referenceNode) {
164
+ if (referenceNode.parentNode) {
165
+ referenceNode.parentNode.insertBefore(newNode, referenceNode);
166
+ }
167
+ return newNode;
168
+ }
169
+
170
+ /**
171
+ * Remove an element from the DOM.
172
+ * @param {HTMLElement} el
173
+ * @returns {HTMLElement}
174
+ */
175
+ function remove(el) {
176
+ if (el && el.parentNode) {
177
+ el.parentNode.removeChild(el);
178
+ }
179
+ return el;
180
+ }
181
+
182
+ /**
183
+ * Replace an old element with a new one.
184
+ * @param {HTMLElement} oldEl
185
+ * @param {HTMLElement} newEl
186
+ * @returns {HTMLElement}
187
+ */
188
+ function replace(oldEl, newEl) {
189
+ if (oldEl.parentNode) {
190
+ oldEl.parentNode.replaceChild(newEl, oldEl);
191
+ }
192
+ return newEl;
193
+ }
194
+
195
+ /**
196
+ * Clone an element.
197
+ * @param {HTMLElement} el
198
+ * @param {boolean} [deep=true]
199
+ * @returns {HTMLElement}
200
+ */
201
+ function clone(el, deep) {
202
+ return el.cloneNode(deep !== false);
203
+ }
204
+
205
+ /**
206
+ * Remove all children from an element.
207
+ * @param {HTMLElement} el
208
+ * @returns {HTMLElement}
209
+ */
210
+ function empty(el) {
211
+ while (el.firstChild) {
212
+ el.removeChild(el.firstChild);
213
+ }
214
+ return el;
215
+ }
216
+
217
+ /**
218
+ * Wrap an element with a wrapper element.
219
+ * @param {HTMLElement} el
220
+ * @param {HTMLElement} wrapper
221
+ * @returns {HTMLElement}
222
+ */
223
+ function wrap(el, wrapper) {
224
+ if (el.parentNode) {
225
+ el.parentNode.insertBefore(wrapper, el);
226
+ }
227
+ wrapper.appendChild(el);
228
+ return wrapper;
229
+ }
230
+
231
+ /**
232
+ * Unwrap an element (remove its parent, keeping the element).
233
+ * @param {HTMLElement} el
234
+ * @returns {HTMLElement}
235
+ */
236
+ function unwrap(el) {
237
+ const parent = el.parentNode;
238
+ if (!parent) return el;
239
+
240
+ while (el.firstChild) {
241
+ parent.insertBefore(el.firstChild, el);
242
+ }
243
+ parent.removeChild(el);
244
+ return parent;
245
+ }
246
+
247
+ // ─── CSS Manipulation ─────────────────────────────────────────────────────────
248
+
249
+ /**
250
+ * Add one or more CSS classes to an element.
251
+ * @param {HTMLElement} el
252
+ * @param {...string} classes
253
+ * @returns {HTMLElement}
254
+ */
255
+ function addClass(el) {
256
+ const classes = Array.prototype.slice.call(arguments, 1);
257
+ el.classList.add.apply(el.classList, classes);
258
+ return el;
259
+ }
260
+
261
+ /**
262
+ * Remove one or more CSS classes from an element.
263
+ * @param {HTMLElement} el
264
+ * @param {...string} classes
265
+ * @returns {HTMLElement}
266
+ */
267
+ function removeClass(el) {
268
+ const classes = Array.prototype.slice.call(arguments, 1);
269
+ el.classList.remove.apply(el.classList, classes);
270
+ return el;
271
+ }
272
+
273
+ /**
274
+ * Toggle a CSS class on an element.
275
+ * @param {HTMLElement} el
276
+ * @param {string} className
277
+ * @param {boolean} [force]
278
+ * @returns {HTMLElement}
279
+ */
280
+ function toggleClass(el, className, force) {
281
+ el.classList.toggle(className, force);
282
+ return el;
283
+ }
284
+
285
+ /**
286
+ * Check if an element has a CSS class.
287
+ * @param {HTMLElement} el
288
+ * @param {string} className
289
+ * @returns {boolean}
290
+ */
291
+ function hasClass(el, className) {
292
+ return el.classList.contains(className);
293
+ }
294
+
295
+ /**
296
+ * Set an inline style property on an element.
297
+ * @param {HTMLElement} el
298
+ * @param {string|Object} prop - CSS property name or style object
299
+ * @param {string} [value] - CSS value (if prop is a string)
300
+ * @returns {HTMLElement}
301
+ */
302
+ function setStyle(el, prop, value) {
303
+ if (typeof prop === 'object') {
304
+ Object.keys(prop).forEach((key) => {
305
+ el.style[key] = prop[key];
306
+ });
307
+ } else {
308
+ el.style[prop] = value;
309
+ }
310
+ return el;
311
+ }
312
+
313
+ /**
314
+ * Get a computed style value for an element.
315
+ * @param {HTMLElement} el
316
+ * @param {string} prop
317
+ * @returns {string}
318
+ */
319
+ function getStyle(el, prop) {
320
+ return window.getComputedStyle(el).getPropertyValue(prop);
321
+ }
322
+
323
+ /**
324
+ * Get all computed styles for an element.
325
+ * @param {HTMLElement} el
326
+ * @returns {CSSStyleDeclaration}
327
+ */
328
+ function getComputedStyle(el) {
329
+ return window.getComputedStyle(el);
330
+ }
331
+
332
+ // ─── Attribute Manipulation ───────────────────────────────────────────────────
333
+
334
+ /**
335
+ * Set an attribute on an element.
336
+ * @param {HTMLElement} el
337
+ * @param {string} name
338
+ * @param {string} value
339
+ * @returns {HTMLElement}
340
+ */
341
+ function setAttribute(el, name, value) {
342
+ el.setAttribute(name, value);
343
+ return el;
344
+ }
345
+
346
+ /**
347
+ * Get an attribute value from an element.
348
+ * @param {HTMLElement} el
349
+ * @param {string} name
350
+ * @returns {string|null}
351
+ */
352
+ function getAttribute(el, name) {
353
+ return el.getAttribute(name);
354
+ }
355
+
356
+ /**
357
+ * Remove an attribute from an element.
358
+ * @param {HTMLElement} el
359
+ * @param {string} name
360
+ * @returns {HTMLElement}
361
+ */
362
+ function removeAttribute(el, name) {
363
+ el.removeAttribute(name);
364
+ return el;
365
+ }
366
+
367
+ /**
368
+ * Set a data attribute on an element.
369
+ * @param {HTMLElement} el
370
+ * @param {string} key
371
+ * @param {*} value
372
+ * @returns {HTMLElement}
373
+ */
374
+ function setData(el, key, value) {
375
+ el.dataset[key] = value;
376
+ return el;
377
+ }
378
+
379
+ /**
380
+ * Get a data attribute from an element.
381
+ * @param {HTMLElement} el
382
+ * @param {string} key
383
+ * @returns {string|undefined}
384
+ */
385
+ function getData(el, key) {
386
+ return el.dataset[key];
387
+ }
388
+
389
+ // ─── Dimension Utilities ──────────────────────────────────────────────────────
390
+
391
+ /**
392
+ * Get the width of an element (content + padding + border).
393
+ * @param {HTMLElement} el
394
+ * @returns {number}
395
+ */
396
+ function getWidth(el) {
397
+ return el.offsetWidth;
398
+ }
399
+
400
+ /**
401
+ * Get the height of an element (content + padding + border).
402
+ * @param {HTMLElement} el
403
+ * @returns {number}
404
+ */
405
+ function getHeight(el) {
406
+ return el.offsetHeight;
407
+ }
408
+
409
+ /**
410
+ * Get the offset position of an element relative to the document.
411
+ * @param {HTMLElement} el
412
+ * @returns {{ top: number, left: number }}
413
+ */
414
+ function getOffset(el) {
415
+ const rect = el.getBoundingClientRect();
416
+ return {
417
+ top: rect.top + window.pageYOffset,
418
+ left: rect.left + window.pageXOffset,
419
+ };
420
+ }
421
+
422
+ /**
423
+ * Get the position of an element relative to its offset parent.
424
+ * @param {HTMLElement} el
425
+ * @returns {{ top: number, left: number }}
426
+ */
427
+ function getPosition(el) {
428
+ return {
429
+ top: el.offsetTop,
430
+ left: el.offsetLeft,
431
+ };
432
+ }
433
+
434
+ /**
435
+ * Get scroll information for an element.
436
+ * @param {HTMLElement} [el=window]
437
+ * @returns {{ top: number, left: number, width: number, height: number }}
438
+ */
439
+ function getScroll(el) {
440
+ if (!el || el === window) {
441
+ return {
442
+ top: window.pageYOffset || document.documentElement.scrollTop,
443
+ left: window.pageXOffset || document.documentElement.scrollLeft,
444
+ width: document.documentElement.scrollWidth,
445
+ height: document.documentElement.scrollHeight,
446
+ };
447
+ }
448
+ return {
449
+ top: el.scrollTop,
450
+ left: el.scrollLeft,
451
+ width: el.scrollWidth,
452
+ height: el.scrollHeight,
453
+ };
454
+ }
455
+
456
+ /**
457
+ * Get viewport dimensions.
458
+ * @returns {{ width: number, height: number }}
459
+ */
460
+ function getViewport() {
461
+ return {
462
+ width: window.innerWidth || document.documentElement.clientWidth,
463
+ height: window.innerHeight || document.documentElement.clientHeight,
464
+ };
465
+ }
466
+
467
+ /**
468
+ * Get the bounding client rect of an element.
469
+ * @param {HTMLElement} el
470
+ * @returns {DOMRect}
471
+ */
472
+ function getRect(el) {
473
+ return el.getBoundingClientRect();
474
+ }
475
+
476
+ // ─── Visibility ───────────────────────────────────────────────────────────────
477
+
478
+ /**
479
+ * Show a hidden element.
480
+ * @param {HTMLElement} el
481
+ * @param {string} [display='']
482
+ * @returns {HTMLElement}
483
+ */
484
+ function show(el, display) {
485
+ el.style.display = display || '';
486
+ return el;
487
+ }
488
+
489
+ /**
490
+ * Hide an element.
491
+ * @param {HTMLElement} el
492
+ * @returns {HTMLElement}
493
+ */
494
+ function hide(el) {
495
+ el.style.display = 'none';
496
+ return el;
497
+ }
498
+
499
+ /**
500
+ * Toggle element visibility.
501
+ * @param {HTMLElement} el
502
+ * @returns {HTMLElement}
503
+ */
504
+ function toggle(el) {
505
+ if (el.style.display === 'none') {
506
+ show(el);
507
+ } else {
508
+ hide(el);
509
+ }
510
+ return el;
511
+ }
512
+
513
+ /**
514
+ * Check if an element is visible (not display:none or visibility:hidden).
515
+ * @param {HTMLElement} el
516
+ * @returns {boolean}
517
+ */
518
+ function isVisible(el) {
519
+ if (el.offsetWidth === 0 && el.offsetHeight === 0) return false;
520
+ const style = window.getComputedStyle(el);
521
+ return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
522
+ }
523
+
524
+ /**
525
+ * Check if an element is within the viewport.
526
+ * @param {HTMLElement} el
527
+ * @param {number} [threshold=0]
528
+ * @returns {boolean}
529
+ */
530
+ function isInViewport(el, threshold) {
531
+ threshold = threshold || 0;
532
+ const rect = el.getBoundingClientRect();
533
+ const vp = getViewport();
534
+
535
+ return (
536
+ rect.top >= -threshold &&
537
+ rect.left >= -threshold &&
538
+ rect.bottom <= vp.height + threshold &&
539
+ rect.right <= vp.width + threshold
540
+ );
541
+ }
542
+
543
+ // ─── Animation Helpers ────────────────────────────────────────────────────────
544
+
545
+ /**
546
+ * Animate an element using the Web Animations API or CSS transitions.
547
+ * @param {HTMLElement} el
548
+ * @param {Object} keyframes
549
+ * @param {Object} [options]
550
+ * @returns {Promise}
551
+ */
552
+ function animate(el, keyframes, options) {
553
+ if (el.animate && typeof el.animate === 'function') {
554
+ return el.animate(keyframes, options).finished;
555
+ }
556
+
557
+ // Fallback: apply final state immediately
558
+ return new Promise((resolve) => {
559
+ Object.keys(keyframes).forEach((prop) => {
560
+ const value = Array.isArray(keyframes[prop])
561
+ ? keyframes[prop][keyframes[prop].length - 1]
562
+ : keyframes[prop];
563
+ el.style[prop] = value;
564
+ });
565
+ requestAnimationFrame(() => resolve(el));
566
+ });
567
+ }
568
+
569
+ /**
570
+ * Fade in an element.
571
+ * @param {HTMLElement} el
572
+ * @param {number} [duration=300]
573
+ * @returns {Promise}
574
+ */
575
+ function fadeIn(el, duration) {
576
+ duration = duration || 300;
577
+ el.style.opacity = '0';
578
+ el.style.display = '';
579
+ return animate(el, { opacity: [0, 1] }, { duration, fill: 'forwards' });
580
+ }
581
+
582
+ /**
583
+ * Fade out an element.
584
+ * @param {HTMLElement} el
585
+ * @param {number} [duration=300]
586
+ * @returns {Promise}
587
+ */
588
+ function fadeOut(el, duration) {
589
+ duration = duration || 300;
590
+ return animate(el, { opacity: [1, 0] }, { duration, fill: 'forwards' }).then(() => {
591
+ el.style.display = 'none';
592
+ return el;
593
+ });
594
+ }
595
+
596
+ /**
597
+ * Slide up (collapse) an element.
598
+ * @param {HTMLElement} el
599
+ * @param {number} [duration=300]
600
+ * @returns {Promise}
601
+ */
602
+ function slideUp(el, duration) {
603
+ duration = duration || 300;
604
+ const height = el.offsetHeight;
605
+ return animate(el, {
606
+ height: [height + 'px', '0px'],
607
+ overflow: ['hidden', 'hidden'],
608
+ }, { duration, fill: 'forwards' }).then(() => {
609
+ el.style.display = 'none';
610
+ return el;
611
+ });
612
+ }
613
+
614
+ /**
615
+ * Slide down (expand) an element.
616
+ * @param {HTMLElement} el
617
+ * @param {number} [duration=300]
618
+ * @returns {Promise}
619
+ */
620
+ function slideDown(el, duration) {
621
+ duration = duration || 300;
622
+ el.style.display = '';
623
+ el.style.overflow = 'hidden';
624
+ const height = el.scrollHeight;
625
+ el.style.height = '0px';
626
+ return animate(el, { height: ['0px', height + 'px'] }, { duration, fill: 'forwards' }).then(() => {
627
+ el.style.height = '';
628
+ el.style.overflow = '';
629
+ return el;
630
+ });
631
+ }
632
+
633
+ /**
634
+ * Toggle slide up/down.
635
+ * @param {HTMLElement} el
636
+ * @param {number} [duration=300]
637
+ * @returns {Promise}
638
+ */
639
+ function slideToggle(el, duration) {
640
+ if (el.style.display === 'none' || el.offsetHeight === 0) {
641
+ return slideDown(el, duration);
642
+ }
643
+ return slideUp(el, duration);
644
+ }
645
+
646
+ // ─── Exports ──────────────────────────────────────────────────────────────────
647
+
648
+ module.exports = {
649
+ // Query selectors
650
+ byId, byClass, byTag, query, queryAll,
651
+ // DOM creation
652
+ createElement, createFragment, createTextNode,
653
+ // DOM manipulation
654
+ append, prepend, insertBefore, remove, replace, clone, empty, wrap, unwrap,
655
+ // CSS manipulation
656
+ addClass, removeClass, toggleClass, hasClass, setStyle, getStyle, getComputedStyle,
657
+ // Attribute manipulation
658
+ setAttribute, getAttribute, removeAttribute, setData, getData,
659
+ // Dimension utilities
660
+ getWidth, getHeight, getOffset, getPosition, getScroll, getViewport, getRect,
661
+ // Visibility
662
+ show, hide, toggle, isVisible, isInViewport,
663
+ // Animation helpers
664
+ animate, fadeIn, fadeOut, slideUp, slideDown, slideToggle,
665
+ };