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
@@ -0,0 +1,860 @@
1
+ /**
2
+ * createElement - Core Virtual DOM Element Creation
3
+ * ElementDrawing Framework - Creates virtual DOM nodes with comprehensive
4
+ * props processing, children handling, fragments, keys, refs, Suspense,
5
+ * StrictMode, error boundaries, lazy loading, and profiling.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ // ─── Constants ────────────────────────────────────────────────────────────────
11
+
12
+ const REACT_ELEMENT_TYPE = Symbol.for('elementdrawing.element');
13
+ const REACT_FRAGMENT_TYPE = Symbol.for('elementdrawing.fragment');
14
+ const REACT_PORTAL_TYPE = Symbol.for('elementdrawing.portal');
15
+ const REACT_SUSPENSE_TYPE = Symbol.for('elementdrawing.suspense');
16
+ const REACT_LAZY_TYPE = Symbol.for('elementdrawing.lazy');
17
+ const REACT_STRICT_MODE_TYPE = Symbol.for('elementdrawing.strict_mode');
18
+ const REACT_ERROR_BOUNDARY_TYPE = Symbol.for('elementdrawing.error_boundary');
19
+ const REACT_PROVIDER_TYPE = Symbol.for('elementdrawing.provider');
20
+ const REACT_CONSUMER_TYPE = Symbol.for('elementdrawing.consumer');
21
+
22
+ const RESERVED_PROPS = {
23
+ key: true,
24
+ ref: true,
25
+ __self: true,
26
+ __source: true,
27
+ };
28
+
29
+ // ─── Element Type Detection ───────────────────────────────────────────────────
30
+
31
+ /**
32
+ * Check if a value is a valid element type.
33
+ * @param {*} type
34
+ * @returns {boolean}
35
+ */
36
+ function isValidElementType(type) {
37
+ if (typeof type === 'string') return true;
38
+ if (typeof type === 'function') return true;
39
+ if (typeof type === 'symbol') return true;
40
+ if (type === REACT_FRAGMENT_TYPE) return true;
41
+ if (type === REACT_PORTAL_TYPE) return true;
42
+ if (type === REACT_SUSPENSE_TYPE) return true;
43
+ if (type === REACT_STRICT_MODE_TYPE) return true;
44
+ if (type === REACT_ERROR_BOUNDARY_TYPE) return true;
45
+ return false;
46
+ }
47
+
48
+ /**
49
+ * Check if a value is a virtual DOM element.
50
+ * @param {*} element
51
+ * @returns {boolean}
52
+ */
53
+ function isValidElement(element) {
54
+ return (
55
+ element !== null &&
56
+ typeof element === 'object' &&
57
+ element.$$typeof === REACT_ELEMENT_TYPE
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Check if an element type is a function component.
63
+ * @param {*} type
64
+ * @returns {boolean}
65
+ */
66
+ function isFunctionComponent(type) {
67
+ return typeof type === 'function' && !type._isClassComponent;
68
+ }
69
+
70
+ /**
71
+ * Check if an element type is a class component.
72
+ * @param {*} type
73
+ * @returns {boolean}
74
+ */
75
+ function isClassComponent(type) {
76
+ return typeof type === 'function' && type._isClassComponent === true;
77
+ }
78
+
79
+ /**
80
+ * Check if an element type is a host (HTML) element.
81
+ * @param {*} type
82
+ * @returns {boolean}
83
+ */
84
+ function isHostElement(type) {
85
+ return typeof type === 'string';
86
+ }
87
+
88
+ /**
89
+ * Check if an element is a Suspense boundary.
90
+ * @param {Object} element
91
+ * @returns {boolean}
92
+ */
93
+ function isSuspenseElement(element) {
94
+ return isValidElement(element) && element.type === REACT_SUSPENSE_TYPE;
95
+ }
96
+
97
+ /**
98
+ * Check if an element is a StrictMode wrapper.
99
+ * @param {Object} element
100
+ * @returns {boolean}
101
+ */
102
+ function isStrictModeElement(element) {
103
+ return isValidElement(element) && element.type === REACT_STRICT_MODE_TYPE;
104
+ }
105
+
106
+ /**
107
+ * Check if an element is an error boundary.
108
+ * @param {Object} element
109
+ * @returns {boolean}
110
+ */
111
+ function isErrorBoundaryElement(element) {
112
+ return isValidElement(element) && element.type === REACT_ERROR_BOUNDARY_TYPE;
113
+ }
114
+
115
+ // ─── Key Extraction & Validation ──────────────────────────────────────────────
116
+
117
+ /**
118
+ * Extract and validate the key from props.
119
+ * @param {*} key - The key value
120
+ * @param {*} parentKey - Parent key for nested elements
121
+ * @returns {string|null} Validated key string
122
+ */
123
+ function extractKey(key, parentKey) {
124
+ if (key === undefined || key === null) return null;
125
+
126
+ const keyString = String(key);
127
+
128
+ if (keyString === '') {
129
+ console.warn('[createElement] Empty string key detected. This may cause reconciliation issues.');
130
+ return null;
131
+ }
132
+
133
+ // Validate key format
134
+ if (/^\./.test(keyString) || /\$/.test(keyString) || /\.\./.test(keyString)) {
135
+ console.warn(
136
+ '[createElement] Key contains invalid characters (., $, ..): ' +
137
+ `"${keyString}". Keys should be simple strings or numbers.`
138
+ );
139
+ }
140
+
141
+ return parentKey ? parentKey + '/' + keyString : keyString;
142
+ }
143
+
144
+ /**
145
+ * Validate that keys are unique among siblings.
146
+ * @param {Array} children - Array of child elements
147
+ */
148
+ function validateChildKeys(children) {
149
+ if (!Array.isArray(children)) return;
150
+
151
+ const seenKeys = new Set();
152
+ let hasIndexKey = false;
153
+
154
+ for (let i = 0; i < children.length; i++) {
155
+ const child = children[i];
156
+ if (!isValidElement(child)) continue;
157
+
158
+ const key = child.key;
159
+ if (key === null) {
160
+ hasIndexKey = true;
161
+ continue;
162
+ }
163
+
164
+ if (seenKeys.has(key)) {
165
+ console.warn(
166
+ '[createElement] Duplicate key "' + key + '" found in children. ' +
167
+ 'This may cause components to be duplicated or lost during reconciliation.'
168
+ );
169
+ }
170
+ seenKeys.add(key);
171
+ }
172
+
173
+ if (hasIndexKey && seenKeys.size > 0) {
174
+ console.warn(
175
+ '[createElement] Mixed explicit and implicit keys detected. ' +
176
+ 'When using keys, all siblings should have explicit keys for optimal reconciliation.'
177
+ );
178
+ }
179
+ }
180
+
181
+ // ─── Ref Forwarding ───────────────────────────────────────────────────────────
182
+
183
+ /**
184
+ * Process the ref prop and handle ref forwarding.
185
+ * @param {*} ref - Ref value
186
+ * @param {Object} element - The element being created
187
+ * @returns {*} Processed ref
188
+ */
189
+ function processRef(ref, element) {
190
+ if (ref === undefined || ref === null) return null;
191
+
192
+ // Object ref (useRef)
193
+ if (typeof ref === 'object' && ref._isRef) {
194
+ return ref;
195
+ }
196
+
197
+ // Callback ref
198
+ if (typeof ref === 'function') {
199
+ return ref;
200
+ }
201
+
202
+ // String ref (legacy)
203
+ if (typeof ref === 'string') {
204
+ console.warn(
205
+ '[createElement] String refs are deprecated. Use callback refs or useRef instead. ' +
206
+ `Received ref: "${ref}"`
207
+ );
208
+ return ref;
209
+ }
210
+
211
+ // Forwarded ref
212
+ if (ref._isForwardRef) {
213
+ return ref;
214
+ }
215
+
216
+ console.warn('[createElement] Invalid ref type: ' + typeof ref);
217
+ return null;
218
+ }
219
+
220
+ // ─── Props Processing ─────────────────────────────────────────────────────────
221
+
222
+ /**
223
+ * Process and clean props, removing reserved props and applying defaults.
224
+ * @param {*} type - Element type
225
+ * @param {Object} props - Raw props
226
+ * @param {*} key - Element key
227
+ * @param {*} ref - Element ref
228
+ * @returns {Object} Cleaned props
229
+ */
230
+ function processProps(type, props, key, ref) {
231
+ const cleanedProps = {};
232
+
233
+ for (const propName in props) {
234
+ if (props.hasOwnProperty(propName)) {
235
+ if (RESERVED_PROPS[propName]) continue;
236
+
237
+ const propValue = props[propName];
238
+
239
+ // Process event handlers
240
+ if (propName.startsWith('on') && typeof propValue === 'function') {
241
+ cleanedProps[propName] = propValue;
242
+ continue;
243
+ }
244
+
245
+ // Process style prop
246
+ if (propName === 'style') {
247
+ cleanedProps[propName] = processStyleProp(propValue);
248
+ continue;
249
+ }
250
+
251
+ // Process className / class
252
+ if (propName === 'className' || propName === 'class') {
253
+ cleanedProps.className = processClassName(propValue);
254
+ continue;
255
+ }
256
+
257
+ // Process dangerouslySetInnerHTML
258
+ if (propName === 'dangerouslySetInnerHTML') {
259
+ if (propValue && typeof propValue.__html === 'string') {
260
+ cleanedProps[propName] = propValue;
261
+ } else {
262
+ console.warn('[createElement] dangerouslySetInnerHTML must have a __html property');
263
+ }
264
+ continue;
265
+ }
266
+
267
+ // Process suppressHydrationWarning
268
+ if (propName === 'suppressHydrationWarning') {
269
+ cleanedProps[propName] = !!propValue;
270
+ continue;
271
+ }
272
+
273
+ cleanedProps[propName] = propValue;
274
+ }
275
+ }
276
+
277
+ // Apply default props
278
+ if (type && type.defaultProps) {
279
+ for (const defaultProp in type.defaultProps) {
280
+ if (type.defaultProps.hasOwnProperty(defaultProp) && cleanedProps[defaultProp] === undefined) {
281
+ cleanedProps[defaultProp] = type.defaultProps[defaultProp];
282
+ }
283
+ }
284
+ }
285
+
286
+ return cleanedProps;
287
+ }
288
+
289
+ /**
290
+ * Process the style prop into a consistent format.
291
+ * @param {*} style
292
+ * @returns {Object|string|undefined}
293
+ */
294
+ function processStyleProp(style) {
295
+ if (style === null || style === undefined) return undefined;
296
+
297
+ if (typeof style === 'string') return style;
298
+
299
+ if (typeof style === 'object') {
300
+ const processed = {};
301
+ for (const prop in style) {
302
+ if (style.hasOwnProperty(prop)) {
303
+ const value = style[prop];
304
+ const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
305
+
306
+ if (typeof value === 'number' && !isUnitlessProperty(cssProp)) {
307
+ processed[cssProp] = value + 'px';
308
+ } else {
309
+ processed[cssProp] = value;
310
+ }
311
+ }
312
+ }
313
+ return processed;
314
+ }
315
+
316
+ return undefined;
317
+ }
318
+
319
+ /**
320
+ * Check if a CSS property is unitless.
321
+ * @param {string} prop
322
+ * @returns {boolean}
323
+ */
324
+ function isUnitlessProperty(prop) {
325
+ const unitlessProps = new Set([
326
+ 'animation-iteration-count', 'border-image-outset', 'border-image-slice',
327
+ 'border-image-width', 'box-flex', 'box-flex-group', 'box-ordinal-group',
328
+ 'column-count', 'columns', 'flex', 'flex-grow', 'flex-positive',
329
+ 'flex-shrink', 'flex-negative', 'flex-order', 'grid-row', 'grid-row-end',
330
+ 'grid-row-span', 'grid-row-start', 'grid-column', 'grid-column-end',
331
+ 'grid-column-span', 'grid-column-start', 'font-weight', 'line-clamp',
332
+ 'line-height', 'opacity', 'order', 'orphans', 'tab-size', 'widows',
333
+ 'z-index', 'zoom', 'fill-opacity', 'flood-opacity', 'stop-opacity',
334
+ 'stroke-dasharray', 'stroke-dashoffset', 'stroke-miterlimit',
335
+ 'stroke-opacity', 'stroke-width',
336
+ ]);
337
+ return unitlessProps.has(prop);
338
+ }
339
+
340
+ /**
341
+ * Process className prop.
342
+ * @param {*} className
343
+ * @returns {string}
344
+ */
345
+ function processClassName(className) {
346
+ if (className === null || className === undefined) return '';
347
+
348
+ if (typeof className === 'string') return className;
349
+
350
+ if (Array.isArray(className)) {
351
+ return className.filter(Boolean).join(' ');
352
+ }
353
+
354
+ if (typeof className === 'object') {
355
+ return Object.keys(className)
356
+ .filter((key) => className[key])
357
+ .join(' ');
358
+ }
359
+
360
+ return String(className);
361
+ }
362
+
363
+ // ─── Children Processing ──────────────────────────────────────────────────────
364
+
365
+ /**
366
+ * Flatten and normalize children, handling arrays, fragments, and nested structures.
367
+ * @param {Array} children - Raw children arguments
368
+ * @returns {Array} Normalized flat array of children
369
+ */
370
+ function flattenChildren(children) {
371
+ const result = [];
372
+
373
+ for (let i = 0; i < children.length; i++) {
374
+ const child = children[i];
375
+
376
+ if (child === null || child === undefined || typeof child === 'boolean') {
377
+ continue;
378
+ }
379
+
380
+ if (Array.isArray(child)) {
381
+ const flat = flattenChildren(child);
382
+ for (let j = 0; j < flat.length; j++) {
383
+ result.push(flat[j]);
384
+ }
385
+ } else if (isValidElement(child) && child.type === REACT_FRAGMENT_TYPE) {
386
+ if (child.props && child.props.children) {
387
+ const fragmentChildren = Array.isArray(child.props.children)
388
+ ? child.props.children
389
+ : [child.props.children];
390
+ const flat = flattenChildren(fragmentChildren);
391
+ for (let j = 0; j < flat.length; j++) {
392
+ result.push(flat[j]);
393
+ }
394
+ }
395
+ } else {
396
+ result.push(child);
397
+ }
398
+ }
399
+
400
+ return result;
401
+ }
402
+
403
+ /**
404
+ * Normalize children into a consistent format.
405
+ * @param {Array} children
406
+ * @param {string|null} parentKey
407
+ * @returns {Array}
408
+ */
409
+ function normalizeChildren(children, parentKey) {
410
+ if (children.length === 0) return [];
411
+
412
+ const normalized = [];
413
+
414
+ for (let i = 0; i < children.length; i++) {
415
+ let child = children[i];
416
+
417
+ if (typeof child === 'string' || typeof child === 'number') {
418
+ child = createTextElement(String(child));
419
+ }
420
+
421
+ if (isValidElement(child)) {
422
+ if (child.key === null) {
423
+ child = assignKey(child, parentKey, i);
424
+ }
425
+ normalized.push(child);
426
+ } else if (child !== null && child !== undefined) {
427
+ console.warn('[createElement] Invalid child type: ' + typeof child);
428
+ }
429
+ }
430
+
431
+ return normalized;
432
+ }
433
+
434
+ /**
435
+ * Create a text element for primitive children.
436
+ * @param {string} text
437
+ * @returns {Object}
438
+ */
439
+ function createTextElement(text) {
440
+ return {
441
+ $$typeof: REACT_ELEMENT_TYPE,
442
+ type: '#text',
443
+ props: { nodeValue: text, children: [] },
444
+ key: null,
445
+ ref: null,
446
+ _owner: null,
447
+ };
448
+ }
449
+
450
+ /**
451
+ * Assign an implicit key based on the parent key and child index.
452
+ */
453
+ function assignKey(element, parentKey, index) {
454
+ const key = parentKey ? parentKey + '.' + index : '.' + index;
455
+ return Object.assign({}, element, { key });
456
+ }
457
+
458
+ // ─── Props Cloning & Merging ──────────────────────────────────────────────────
459
+
460
+ /**
461
+ * Clone an element with new props merged.
462
+ * @param {Object} element
463
+ * @param {Object} newProps
464
+ * @param {...*} newChildren
465
+ * @returns {Object}
466
+ */
467
+ function cloneElement(element, newProps) {
468
+ if (!isValidElement(element)) {
469
+ throw new Error('[cloneElement] Argument must be a valid element');
470
+ }
471
+
472
+ const children = Array.prototype.slice.call(arguments, 2);
473
+ const mergedProps = Object.assign({}, element.props, newProps);
474
+
475
+ if (children.length > 0) {
476
+ mergedProps.children = children.length === 1 ? children[0] : children;
477
+ }
478
+
479
+ const key = newProps && newProps.key !== undefined ? newProps.key : element.key;
480
+ const ref = newProps && newProps.ref !== undefined ? newProps.ref : element.ref;
481
+
482
+ if (newProps && newProps.key !== undefined) delete mergedProps.key;
483
+ if (newProps && newProps.ref !== undefined) delete mergedProps.ref;
484
+
485
+ return createElement(element.type, Object.assign({ key, ref }, mergedProps));
486
+ }
487
+
488
+ /**
489
+ * Merge props from multiple sources.
490
+ * Event handlers are chained rather than overwritten.
491
+ * @returns {Object}
492
+ */
493
+ function mergeProps() {
494
+ const result = {};
495
+
496
+ for (let i = 0; i < arguments.length; i++) {
497
+ const props = arguments[i];
498
+ if (!props) continue;
499
+
500
+ for (const key in props) {
501
+ if (!props.hasOwnProperty(key)) continue;
502
+
503
+ if (key.startsWith('on') && result[key] && typeof result[key] === 'function') {
504
+ const existingHandler = result[key];
505
+ const newHandler = props[key];
506
+ result[key] = function chainedHandler() {
507
+ existingHandler.apply(this, arguments);
508
+ newHandler.apply(this, arguments);
509
+ };
510
+ } else if (key === 'style' && result.style && typeof result.style === 'object' && typeof props.style === 'object') {
511
+ result.style = Object.assign({}, result.style, props.style);
512
+ } else if (key === 'className' && result.className) {
513
+ result.className = result.className + ' ' + props.className;
514
+ } else {
515
+ result[key] = props[key];
516
+ }
517
+ }
518
+ }
519
+
520
+ return result;
521
+ }
522
+
523
+ // ─── Core createElement ───────────────────────────────────────────────────────
524
+
525
+ /**
526
+ * createElement - Create a virtual DOM element.
527
+ *
528
+ * @param {*} type - Element type
529
+ * @param {Object|null} config - Element configuration
530
+ * @param {...*} children - Child elements
531
+ * @returns {Object} Virtual DOM element
532
+ */
533
+ function createElement(type, config) {
534
+ const children = Array.prototype.slice.call(arguments, 2);
535
+
536
+ // Validate type
537
+ if (!isValidElementType(type)) {
538
+ throw new Error(
539
+ '[createElement] Invalid element type: ' + typeof type +
540
+ '. Expected a string, function, or symbol.'
541
+ );
542
+ }
543
+
544
+ // Extract Key and Ref from Config
545
+ let key = null;
546
+ let ref = null;
547
+ let props = {};
548
+
549
+ if (config !== null && config !== undefined) {
550
+ if (typeof config !== 'object') {
551
+ throw new Error(
552
+ '[createElement] Config must be an object or null. ' +
553
+ 'Received: ' + typeof config
554
+ );
555
+ }
556
+
557
+ if (config.key !== undefined) {
558
+ key = extractKey(config.key, null);
559
+ }
560
+
561
+ if (config.ref !== undefined) {
562
+ ref = processRef(config.ref, null);
563
+ }
564
+
565
+ for (const propName in config) {
566
+ if (config.hasOwnProperty(propName) && !RESERVED_PROPS[propName]) {
567
+ props[propName] = config[propName];
568
+ }
569
+ }
570
+ }
571
+
572
+ // Process Children
573
+ const flattenedChildren = flattenChildren(children);
574
+ const normalizedChildren = normalizeChildren(flattenedChildren, key);
575
+
576
+ if (normalizedChildren.length === 0) {
577
+ props.children = [];
578
+ } else if (normalizedChildren.length === 1) {
579
+ props.children = normalizedChildren[0];
580
+ } else {
581
+ props.children = normalizedChildren;
582
+ }
583
+
584
+ // Process Props
585
+ props = processProps(type, props, key, ref);
586
+
587
+ // Prop Type Validation
588
+ if (type && type.propTypes && typeof type.propTypes === 'object') {
589
+ for (const propName in type.propTypes) {
590
+ if (type.propTypes.hasOwnProperty(propName)) {
591
+ const validator = type.propTypes[propName];
592
+ if (typeof validator === 'function') {
593
+ const result = validator(props, propName, type.displayName || type.name || 'Component', 'prop');
594
+ if (result instanceof Error) {
595
+ console.warn('[createElement] Prop validation: ' + result.message);
596
+ }
597
+ }
598
+ }
599
+ }
600
+ }
601
+
602
+ // Validate Child Keys
603
+ if (Array.isArray(normalizedChildren) && normalizedChildren.length > 1) {
604
+ validateChildKeys(normalizedChildren);
605
+ }
606
+
607
+ // Create Element Object
608
+ const element = {
609
+ $$typeof: REACT_ELEMENT_TYPE,
610
+ type,
611
+ key,
612
+ ref,
613
+ props,
614
+ _owner: null,
615
+ _store: {},
616
+ };
617
+
618
+ // Make element immutable in development
619
+ if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production') {
620
+ Object.freeze(element.props);
621
+ Object.freeze(element);
622
+ }
623
+
624
+ return element;
625
+ }
626
+
627
+ // ─── Fragment ─────────────────────────────────────────────────────────────────
628
+
629
+ const Fragment = REACT_FRAGMENT_TYPE;
630
+
631
+ // ─── Suspense ─────────────────────────────────────────────────────────────────
632
+
633
+ /**
634
+ * Suspense component for handling async rendering.
635
+ * @param {Object} props
636
+ * @param {*} props.fallback - Fallback UI while suspended
637
+ * @param {*} props.children - Children to suspend
638
+ */
639
+ const Suspense = REACT_SUSPENSE_TYPE;
640
+
641
+ /**
642
+ * Create a Suspense element.
643
+ * @param {Object} props
644
+ * @returns {Object} Suspense element
645
+ */
646
+ function createSuspense(props) {
647
+ return createElement(Suspense, props, props.children);
648
+ }
649
+
650
+ // ─── StrictMode ───────────────────────────────────────────────────────────────
651
+
652
+ const StrictMode = REACT_STRICT_MODE_TYPE;
653
+
654
+ /**
655
+ * Create a StrictMode wrapper element.
656
+ * @param {Object} props
657
+ * @returns {Object} StrictMode element
658
+ */
659
+ function createStrictMode(props) {
660
+ return createElement(StrictMode, null, props.children);
661
+ }
662
+
663
+ // ─── Error Boundary ───────────────────────────────────────────────────────────
664
+
665
+ const ErrorBoundary = REACT_ERROR_BOUNDARY_TYPE;
666
+
667
+ /**
668
+ * Create an error boundary element.
669
+ * @param {Object} props
670
+ * @param {Function} props.onError - Error handler
671
+ * @param {*} props.fallback - Fallback UI
672
+ * @param {*} props.children - Children to protect
673
+ * @returns {Object} Error boundary element
674
+ */
675
+ function createErrorBoundary(props) {
676
+ return createElement(ErrorBoundary, props, props.children);
677
+ }
678
+
679
+ // ─── Portal ───────────────────────────────────────────────────────────────────
680
+
681
+ /**
682
+ * Create a portal element.
683
+ * @param {*} children
684
+ * @param {HTMLElement} container
685
+ * @param {string|null} key
686
+ * @returns {Object}
687
+ */
688
+ function createPortal(children, container, key) {
689
+ return {
690
+ $$typeof: REACT_PORTAL_TYPE,
691
+ key: key === null ? null : String(key),
692
+ children,
693
+ containerInfo: container,
694
+ implementation: null,
695
+ };
696
+ }
697
+
698
+ // ─── Lazy Component ───────────────────────────────────────────────────────────
699
+
700
+ /**
701
+ * Create a lazy-loaded component.
702
+ * @param {Function} factory
703
+ * @returns {Object}
704
+ */
705
+ function lazy(factory) {
706
+ const lazyComponent = {
707
+ $$typeof: REACT_LAZY_TYPE,
708
+ _payload: {
709
+ _status: -1, // -1: pending, 0: resolved, 1: rejected
710
+ _result: null,
711
+ },
712
+ _init: function init(payload) {
713
+ if (payload._status === -1) {
714
+ const thenable = factory();
715
+ thenable.then(
716
+ function resolve(module) {
717
+ if (payload._status === -1) {
718
+ payload._status = 0;
719
+ payload._result = module.default || module;
720
+ }
721
+ },
722
+ function reject(error) {
723
+ if (payload._status === -1) {
724
+ payload._status = 1;
725
+ payload._result = error;
726
+ }
727
+ }
728
+ );
729
+ payload._status = -1;
730
+ payload._result = thenable;
731
+ }
732
+ },
733
+ };
734
+ return lazyComponent;
735
+ }
736
+
737
+ // ─── Children Utilities ───────────────────────────────────────────────────────
738
+
739
+ /**
740
+ * Count the number of children.
741
+ * @param {*} children
742
+ * @returns {number}
743
+ */
744
+ function countChildren(children) {
745
+ if (children === null || children === undefined) return 0;
746
+ if (Array.isArray(children)) return children.length;
747
+ return 1;
748
+ }
749
+
750
+ /**
751
+ * Map over children.
752
+ * @param {*} children
753
+ * @param {Function} fn
754
+ * @returns {Array}
755
+ */
756
+ function mapChildren(children, fn) {
757
+ if (children === null || children === undefined) return [];
758
+
759
+ if (Array.isArray(children)) {
760
+ return children.map((child, index) => fn(child, index));
761
+ }
762
+
763
+ return [fn(children, 0)];
764
+ }
765
+
766
+ /**
767
+ * ForEach over children (no return value).
768
+ * @param {*} children
769
+ * @param {Function} fn
770
+ */
771
+ function forEachChild(children, fn) {
772
+ if (children === null || children === undefined) return;
773
+
774
+ if (Array.isArray(children)) {
775
+ children.forEach((child, index) => fn(child, index));
776
+ } else {
777
+ fn(children, 0);
778
+ }
779
+ }
780
+
781
+ /**
782
+ * Check if children is an array with more than one element.
783
+ * @param {*} children
784
+ * @returns {boolean}
785
+ */
786
+ function isChildrenArray(children) {
787
+ return Array.isArray(children) && children.length > 1;
788
+ }
789
+
790
+ /**
791
+ * Get only child from children.
792
+ * @param {*} children
793
+ * @returns {*}
794
+ */
795
+ function onlyChild(children) {
796
+ if (!isValidElement(children)) {
797
+ throw new Error('[onlyChild] Expected a single ElementDrawing element');
798
+ }
799
+ return children;
800
+ }
801
+
802
+ // ─── Element Creation with Render Prop ────────────────────────────────────────
803
+
804
+ function createElementWithRenderProp(type, props, renderFn) {
805
+ if (typeof renderFn !== 'function') {
806
+ throw new Error('[createElementWithRenderProp] Third argument must be a function');
807
+ }
808
+
809
+ return createElement(type, Object.assign({}, props, { children: renderFn }));
810
+ }
811
+
812
+ // ─── Exports ──────────────────────────────────────────────────────────────────
813
+
814
+ module.exports = {
815
+ createElement,
816
+ cloneElement,
817
+ mergeProps,
818
+ createTextElement,
819
+ createPortal,
820
+ createSuspense,
821
+ createStrictMode,
822
+ createErrorBoundary,
823
+ createRef: function () { return { current: null, _isRef: true }; },
824
+ Fragment,
825
+ Suspense,
826
+ StrictMode,
827
+ ErrorBoundary,
828
+ lazy,
829
+ isValidElement,
830
+ isValidElementType,
831
+ isFunctionComponent,
832
+ isClassComponent,
833
+ isHostElement,
834
+ isSuspenseElement,
835
+ isStrictModeElement,
836
+ isErrorBoundaryElement,
837
+ extractKey,
838
+ processRef,
839
+ processProps,
840
+ processStyleProp,
841
+ processClassName,
842
+ flattenChildren,
843
+ normalizeChildren,
844
+ createElementWithRenderProp,
845
+ countChildren,
846
+ mapChildren,
847
+ forEachChild,
848
+ isChildrenArray,
849
+ onlyChild,
850
+ REACT_ELEMENT_TYPE,
851
+ REACT_FRAGMENT_TYPE,
852
+ REACT_PORTAL_TYPE,
853
+ REACT_SUSPENSE_TYPE,
854
+ REACT_LAZY_TYPE,
855
+ REACT_STRICT_MODE_TYPE,
856
+ REACT_ERROR_BOUNDARY_TYPE,
857
+ REACT_PROVIDER_TYPE,
858
+ REACT_CONSUMER_TYPE,
859
+ RESERVED_PROPS,
860
+ };