@ktjs/core 0.26.9 → 0.27.2

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.
@@ -1,3 +1,38 @@
1
+ // Cached native methods for performance optimization
2
+ const $isArray = Array.isArray;
3
+ const $is = Object.is;
4
+ const $random = Math.random;
5
+ const $isThenable = (o) => typeof o?.then === 'function';
6
+
7
+ if (typeof Symbol === 'undefined') {
8
+ window.Symbol = function Symbol(description) {
9
+ return `@@SYMBOL_${description || ''}_${$random().toString(36).slice(2)}`;
10
+ };
11
+ }
12
+
13
+ // String manipulation utilities
14
+ /**
15
+ * Default empty function
16
+ */
17
+ const $emptyFn = (() => true);
18
+ const $emptyArray = [];
19
+ /**
20
+ * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
21
+ */
22
+ const $forEach = (array, callback) => {
23
+ const len = array.length;
24
+ for (let i = 0; i < len; i++) {
25
+ callback(array[i], i, array);
26
+ }
27
+ };
28
+
29
+ const $emptyChildrenRef = { value: $emptyArray };
30
+ // each instance shares the same empty array, but it will be replaced when used
31
+ Comment.prototype.kisFragmentAnchor = false;
32
+ Comment.prototype.kFragmentList = $emptyArray;
33
+ Comment.prototype.kredraw = $emptyFn;
34
+ Comment.prototype.kchildrenRef = $emptyChildrenRef;
35
+
1
36
  // Shared constants
2
37
  // Empty for now - can be extended with framework-wide constants
3
38
  /**
@@ -9,12 +44,6 @@ const SVG_ATTR_FLAG = '__kt_svg__';
9
44
  */
10
45
  const MATHML_ATTR_FLAG = '__kt_mathml__';
11
46
 
12
- // Cached native methods for performance optimization
13
- const $isArray = Array.isArray;
14
- const $is = Object.is;
15
- const $random = Math.random;
16
- const $isThenable = (o) => typeof o?.then === 'function';
17
-
18
47
  // DOM manipulation utilities
19
48
  // # dom natives
20
49
  const $isNode = (x) => x?.nodeType > 0;
@@ -68,20 +97,14 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
68
97
  /**
69
98
  * Used for `k-model`
70
99
  */
71
- const applyModel = (element, valueRef, propName, eventName) => {
100
+ const $applyModel = (element, valueRef, propName, eventName) => {
72
101
  element[propName] = valueRef.value; // initialize
73
102
  valueRef.addOnChange((newValue) => (element[propName] = newValue));
74
103
  element.addEventListener(eventName, () => (valueRef.value = element[propName]));
75
104
  };
76
105
 
77
- if (typeof Symbol === 'undefined') {
78
- window.Symbol = function Symbol(description) {
79
- return `@@SYMBOL_${description || ''}_${$random().toString(36).slice(2)}`;
80
- };
81
- }
82
-
83
- // Shared utilities and cached native methods for kt.js framework
84
- Object.defineProperty(window, '__ktjs__', { value: '0.23.3' });
106
+ // incase that symbol is not supported
107
+ Object.defineProperty(window, '__ktjs__', { value: '0.23.10' });
85
108
 
86
109
  const isKT = (obj) => obj?.isKT;
87
110
  const isRef = (obj) => obj?.ktType === 1 /* KTReactiveType.REF */;
@@ -237,6 +260,7 @@ function apdSingle(element, c) {
237
260
  else {
238
261
  $append.call(element, c);
239
262
  // Handle KTFor anchor
263
+ // todo Maybe not needed anymore
240
264
  const list = c.__kt_for_list__;
241
265
  if ($isArray(list)) {
242
266
  apd(element, list);
@@ -340,8 +364,31 @@ class KTRef {
340
364
  * @param value mostly an HTMLElement
341
365
  */
342
366
  function ref(value, onChange) {
343
- return new KTRef(value, []);
367
+ return new KTRef(value, onChange ? [onChange] : []);
344
368
  }
369
+ const $setRef = (props, node) => {
370
+ if ('ref' in props) {
371
+ const r = props.ref;
372
+ if (isRef(r)) {
373
+ r.value = node;
374
+ }
375
+ else {
376
+ throw new Error('[kt.js error] Fragment: ref must be a KTRef');
377
+ }
378
+ }
379
+ };
380
+
381
+ const toReactive = (value, onChange) => {
382
+ if (isKT(value)) {
383
+ if (onChange) {
384
+ value.addOnChange(onChange);
385
+ }
386
+ return value;
387
+ }
388
+ else {
389
+ return ref(value, onChange);
390
+ }
391
+ };
345
392
 
346
393
  function applyKModel(element, valueRef) {
347
394
  if (!isKT(valueRef)) {
@@ -350,17 +397,17 @@ function applyKModel(element, valueRef) {
350
397
  }
351
398
  if (element instanceof HTMLInputElement) {
352
399
  if (element.type === 'radio' || element.type === 'checkbox') {
353
- applyModel(element, valueRef, 'checked', 'change');
400
+ $applyModel(element, valueRef, 'checked', 'change');
354
401
  }
355
402
  else {
356
- applyModel(element, valueRef, 'value', 'input');
403
+ $applyModel(element, valueRef, 'value', 'input');
357
404
  }
358
405
  }
359
406
  else if (element instanceof HTMLSelectElement) {
360
- applyModel(element, valueRef, 'value', 'change');
407
+ $applyModel(element, valueRef, 'value', 'change');
361
408
  }
362
409
  else if (element instanceof HTMLTextAreaElement) {
363
- applyModel(element, valueRef, 'value', 'input');
410
+ $applyModel(element, valueRef, 'value', 'input');
364
411
  }
365
412
  else {
366
413
  console.warn('[kt.js warn]','not supported element for k-model:');
@@ -381,7 +428,7 @@ let creator = htmlCreator;
381
428
  * ## About
382
429
  * @package @ktjs/core
383
430
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
384
- * @version 0.26.9 (Last Update: 2026.02.06 16:29:24.402)
431
+ * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
385
432
  * @license MIT
386
433
  * @link https://github.com/baendlorel/kt.js
387
434
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -416,7 +463,110 @@ const h = (tag, attr, content) => {
416
463
  return element;
417
464
  };
418
465
 
419
- const dummyRef = { value: null };
466
+ const kredraw = function () {
467
+ const newElements = this.kchildrenRef.value;
468
+ const parent = this.parentNode;
469
+ if (!parent) {
470
+ // If anchor is not in DOM, only update internal state
471
+ this.kFragmentList.length = 0;
472
+ for (let i = 0; i < newElements.length; i++) {
473
+ this.kFragmentList.push(newElements[i]);
474
+ }
475
+ return;
476
+ }
477
+ // Simple replacement algorithm: remove all old elements, insert all new elements
478
+ // todo Future enhancement: key-based optimization
479
+ // 1. Remove all old elements
480
+ for (let i = 0; i < this.kFragmentList.length; i++) {
481
+ this.kFragmentList[i].remove();
482
+ }
483
+ // 2. Insert all new elements
484
+ const fragment = document.createDocumentFragment();
485
+ this.kFragmentList.length = 0;
486
+ for (let i = 0; i < newElements.length; i++) {
487
+ const element = newElements[i];
488
+ this.kFragmentList.push(element);
489
+ fragment.appendChild(element);
490
+ }
491
+ // Insert after anchor
492
+ parent.insertBefore(fragment, this.nextSibling);
493
+ };
494
+ /**
495
+ * Fragment - Container component for managing arrays of child elements
496
+ *
497
+ * Features:
498
+ * 1. Returns a comment anchor node, child elements are inserted after the anchor
499
+ * 2. Supports reactive arrays, automatically updates DOM when array changes
500
+ * 3. Basic version uses simple replacement algorithm (remove all old elements, insert all new elements)
501
+ * 4. Future enhancement: key-based optimization
502
+ *
503
+ * Usage example:
504
+ * ```tsx
505
+ * const children = ref([<div>A</div>, <div>B</div>]);
506
+ * const fragment = <Fragment children={children} />;
507
+ * document.body.appendChild(fragment);
508
+ *
509
+ * // Automatic update
510
+ * children.value = [<div>C</div>, <div>D</div>];
511
+ * ```
512
+ */
513
+ function Fragment$1(props) {
514
+ // key parameter reserved for future enhancement, currently unused
515
+ const { key: _key } = props;
516
+ const childrenRef = toReactive(props.children, () => anchor.kredraw());
517
+ const anchor = document.createComment('kt-fragment');
518
+ anchor.kredraw = kredraw;
519
+ anchor.kchildrenRef = childrenRef;
520
+ anchor.kFragmentList = [];
521
+ anchor.kisFragmentAnchor = true;
522
+ // Observe DOM insertion
523
+ const observer = new MutationObserver(() => {
524
+ if (anchor.isConnected) {
525
+ anchor.kredraw();
526
+ observer.disconnect();
527
+ }
528
+ });
529
+ observer.observe(document.body, { childList: true, subtree: true });
530
+ // Set ref reference
531
+ $setRef(props, anchor);
532
+ return anchor;
533
+ }
534
+ /**
535
+ * Convert KTRawContent to HTMLElement array
536
+ */
537
+ function convertChildrenToElements(children) {
538
+ const elements = [];
539
+ const processChild = (child) => {
540
+ if (child == null || child === false || child === true) {
541
+ // Ignore null, undefined, false, true
542
+ return;
543
+ }
544
+ if ($isArray(child)) {
545
+ // Recursively process array
546
+ $forEach(child, processChild);
547
+ return;
548
+ }
549
+ if (typeof child === 'string' || typeof child === 'number') {
550
+ // & Wrap text in span element? No! use text node instead
551
+ const textNode = document.createTextNode(String(child));
552
+ elements.push(textNode);
553
+ return;
554
+ }
555
+ if (child instanceof HTMLElement) {
556
+ elements.push(child);
557
+ return;
558
+ }
559
+ if (isKT(child)) {
560
+ processChild(child.value);
561
+ return;
562
+ }
563
+ // Other types ignored or converted to string
564
+ console.warn('[kt.js warn]','Fragment: unsupported child type', child);
565
+ };
566
+ processChild(children);
567
+ return elements;
568
+ }
569
+
420
570
  const create = (tag, props) => {
421
571
  if (typeof tag === 'function') {
422
572
  return tag(props);
@@ -434,7 +584,6 @@ function jsx(tag, props) {
434
584
  if (isComputed(props.ref)) {
435
585
  throw new Error('[kt.js error] Cannot assign a computed value to an element.');
436
586
  }
437
- const maybeDummyRef = isRef(props.ref) ? props.ref : dummyRef;
438
587
  let el;
439
588
  if ('k-if' in props) {
440
589
  const kif = props['k-if'];
@@ -446,49 +595,31 @@ function jsx(tag, props) {
446
595
  return;
447
596
  }
448
597
  const oldEl = el;
449
- el = newValue ? create(tag, props) : placeholder();
598
+ $setRef(props, (el = newValue ? create(tag, props) : placeholder()));
450
599
  $replaceNode(oldEl, el);
451
- maybeDummyRef.value = el;
452
600
  });
453
601
  condition = kif.value;
454
602
  }
455
603
  if (!condition) {
456
604
  // & make comment placeholder in case that ref might be redrawn later
457
- el = placeholder();
458
- maybeDummyRef.value = el;
605
+ $setRef(props, (el = placeholder()));
459
606
  return el;
460
607
  }
461
608
  }
462
- el = create(tag, props);
463
- maybeDummyRef.value = el;
609
+ $setRef(props, (el = create(tag, props)));
464
610
  return el;
465
611
  }
466
612
  /**
467
613
  * Fragment support - returns an array of children
468
- * Note: kt.js doesn't have a real Fragment concept,
614
+ * Enhanced Fragment component that manages arrays of elements
469
615
  */
470
- function Fragment(_props) {
471
- throw new Error("[kt.js error] doesn't have a Fragment concept");
472
- // const { children } = props ?? {};
473
- // if (!children) {
474
- // return ;
475
- // }
476
- // // If single child, return it directly
477
- // if (!Array.isArray(children)) {
478
- // return children as HTMLElement;
479
- // }
480
- // // For multiple children, create a document fragment wrapper
481
- // // This is a limitation - JSX fragments must be wrapped in kt.js
482
- // const wrapper = document.createElement('div');
483
- // wrapper.setAttribute('data-kt-fragment', 'true');
484
- // children.forEach((child) => {
485
- // if (typeof child === 'string') {
486
- // wrapper.appendChild(document.createTextNode(child));
487
- // } else if (child instanceof HTMLElement) {
488
- // wrapper.appendChild(child);
489
- // }
490
- // });
491
- // return wrapper;
616
+ function Fragment(props) {
617
+ const { children } = props ?? {};
618
+ if (!children) {
619
+ return document.createComment('kt-fragment-empty');
620
+ }
621
+ const elements = convertChildrenToElements(children);
622
+ return Fragment$1({ children: elements });
492
623
  }
493
624
  /**
494
625
  * JSX Development runtime - same as jsx but with additional dev checks
@@ -134,7 +134,7 @@ type KTAttribute = KTBaseAttribute & KTPrefixedEventAttribute;
134
134
  * ## About
135
135
  * @package @ktjs/core
136
136
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
137
- * @version 0.26.9 (Last Update: 2026.02.06 16:29:24.402)
137
+ * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
138
138
  * @license MIT
139
139
  * @link https://github.com/baendlorel/kt.js
140
140
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -151,11 +151,11 @@ type JSXTag = HTMLTag | ((props?: any) => HTMLElement) | ((props?: any) => Promi
151
151
  declare function jsx(tag: JSXTag, props: KTAttribute): JSX.Element;
152
152
  /**
153
153
  * Fragment support - returns an array of children
154
- * Note: kt.js doesn't have a real Fragment concept,
154
+ * Enhanced Fragment component that manages arrays of elements
155
155
  */
156
- declare function Fragment(_props: {
156
+ declare function Fragment(props: {
157
157
  children?: KTRawContent;
158
- }): HTMLElement;
158
+ }): JSX.Element;
159
159
  /**
160
160
  * JSX Development runtime - same as jsx but with additional dev checks
161
161
  */
@@ -1,3 +1,38 @@
1
+ // Cached native methods for performance optimization
2
+ const $isArray = Array.isArray;
3
+ const $is = Object.is;
4
+ const $random = Math.random;
5
+ const $isThenable = (o) => typeof o?.then === 'function';
6
+
7
+ if (typeof Symbol === 'undefined') {
8
+ window.Symbol = function Symbol(description) {
9
+ return `@@SYMBOL_${description || ''}_${$random().toString(36).slice(2)}`;
10
+ };
11
+ }
12
+
13
+ // String manipulation utilities
14
+ /**
15
+ * Default empty function
16
+ */
17
+ const $emptyFn = (() => true);
18
+ const $emptyArray = [];
19
+ /**
20
+ * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
21
+ */
22
+ const $forEach = (array, callback) => {
23
+ const len = array.length;
24
+ for (let i = 0; i < len; i++) {
25
+ callback(array[i], i, array);
26
+ }
27
+ };
28
+
29
+ const $emptyChildrenRef = { value: $emptyArray };
30
+ // each instance shares the same empty array, but it will be replaced when used
31
+ Comment.prototype.kisFragmentAnchor = false;
32
+ Comment.prototype.kFragmentList = $emptyArray;
33
+ Comment.prototype.kredraw = $emptyFn;
34
+ Comment.prototype.kchildrenRef = $emptyChildrenRef;
35
+
1
36
  // Shared constants
2
37
  // Empty for now - can be extended with framework-wide constants
3
38
  /**
@@ -9,12 +44,6 @@ const SVG_ATTR_FLAG = '__kt_svg__';
9
44
  */
10
45
  const MATHML_ATTR_FLAG = '__kt_mathml__';
11
46
 
12
- // Cached native methods for performance optimization
13
- const $isArray = Array.isArray;
14
- const $is = Object.is;
15
- const $random = Math.random;
16
- const $isThenable = (o) => typeof o?.then === 'function';
17
-
18
47
  // DOM manipulation utilities
19
48
  // # dom natives
20
49
  const $isNode = (x) => x?.nodeType > 0;
@@ -68,20 +97,14 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
68
97
  /**
69
98
  * Used for `k-model`
70
99
  */
71
- const applyModel = (element, valueRef, propName, eventName) => {
100
+ const $applyModel = (element, valueRef, propName, eventName) => {
72
101
  element[propName] = valueRef.value; // initialize
73
102
  valueRef.addOnChange((newValue) => (element[propName] = newValue));
74
103
  element.addEventListener(eventName, () => (valueRef.value = element[propName]));
75
104
  };
76
105
 
77
- if (typeof Symbol === 'undefined') {
78
- window.Symbol = function Symbol(description) {
79
- return `@@SYMBOL_${description || ''}_${$random().toString(36).slice(2)}`;
80
- };
81
- }
82
-
83
- // Shared utilities and cached native methods for kt.js framework
84
- Object.defineProperty(window, '__ktjs__', { value: '0.23.3' });
106
+ // incase that symbol is not supported
107
+ Object.defineProperty(window, '__ktjs__', { value: '0.23.10' });
85
108
 
86
109
  const isKT = (obj) => obj?.isKT;
87
110
  const isRef = (obj) => obj?.ktType === 1 /* KTReactiveType.REF */;
@@ -237,6 +260,7 @@ function apdSingle(element, c) {
237
260
  else {
238
261
  $append.call(element, c);
239
262
  // Handle KTFor anchor
263
+ // todo Maybe not needed anymore
240
264
  const list = c.__kt_for_list__;
241
265
  if ($isArray(list)) {
242
266
  apd(element, list);
@@ -340,8 +364,31 @@ class KTRef {
340
364
  * @param value mostly an HTMLElement
341
365
  */
342
366
  function ref(value, onChange) {
343
- return new KTRef(value, []);
367
+ return new KTRef(value, onChange ? [onChange] : []);
344
368
  }
369
+ const $setRef = (props, node) => {
370
+ if ('ref' in props) {
371
+ const r = props.ref;
372
+ if (isRef(r)) {
373
+ r.value = node;
374
+ }
375
+ else {
376
+ throw new Error('[kt.js error] Fragment: ref must be a KTRef');
377
+ }
378
+ }
379
+ };
380
+
381
+ const toReactive = (value, onChange) => {
382
+ if (isKT(value)) {
383
+ if (onChange) {
384
+ value.addOnChange(onChange);
385
+ }
386
+ return value;
387
+ }
388
+ else {
389
+ return ref(value, onChange);
390
+ }
391
+ };
345
392
 
346
393
  function applyKModel(element, valueRef) {
347
394
  if (!isKT(valueRef)) {
@@ -350,17 +397,17 @@ function applyKModel(element, valueRef) {
350
397
  }
351
398
  if (element instanceof HTMLInputElement) {
352
399
  if (element.type === 'radio' || element.type === 'checkbox') {
353
- applyModel(element, valueRef, 'checked', 'change');
400
+ $applyModel(element, valueRef, 'checked', 'change');
354
401
  }
355
402
  else {
356
- applyModel(element, valueRef, 'value', 'input');
403
+ $applyModel(element, valueRef, 'value', 'input');
357
404
  }
358
405
  }
359
406
  else if (element instanceof HTMLSelectElement) {
360
- applyModel(element, valueRef, 'value', 'change');
407
+ $applyModel(element, valueRef, 'value', 'change');
361
408
  }
362
409
  else if (element instanceof HTMLTextAreaElement) {
363
- applyModel(element, valueRef, 'value', 'input');
410
+ $applyModel(element, valueRef, 'value', 'input');
364
411
  }
365
412
  else {
366
413
  console.warn('[kt.js warn]','not supported element for k-model:');
@@ -381,7 +428,7 @@ let creator = htmlCreator;
381
428
  * ## About
382
429
  * @package @ktjs/core
383
430
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
384
- * @version 0.26.9 (Last Update: 2026.02.06 16:29:24.402)
431
+ * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
385
432
  * @license MIT
386
433
  * @link https://github.com/baendlorel/kt.js
387
434
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -416,7 +463,110 @@ const h = (tag, attr, content) => {
416
463
  return element;
417
464
  };
418
465
 
419
- const dummyRef = { value: null };
466
+ const kredraw = function () {
467
+ const newElements = this.kchildrenRef.value;
468
+ const parent = this.parentNode;
469
+ if (!parent) {
470
+ // If anchor is not in DOM, only update internal state
471
+ this.kFragmentList.length = 0;
472
+ for (let i = 0; i < newElements.length; i++) {
473
+ this.kFragmentList.push(newElements[i]);
474
+ }
475
+ return;
476
+ }
477
+ // Simple replacement algorithm: remove all old elements, insert all new elements
478
+ // todo Future enhancement: key-based optimization
479
+ // 1. Remove all old elements
480
+ for (let i = 0; i < this.kFragmentList.length; i++) {
481
+ this.kFragmentList[i].remove();
482
+ }
483
+ // 2. Insert all new elements
484
+ const fragment = document.createDocumentFragment();
485
+ this.kFragmentList.length = 0;
486
+ for (let i = 0; i < newElements.length; i++) {
487
+ const element = newElements[i];
488
+ this.kFragmentList.push(element);
489
+ fragment.appendChild(element);
490
+ }
491
+ // Insert after anchor
492
+ parent.insertBefore(fragment, this.nextSibling);
493
+ };
494
+ /**
495
+ * Fragment - Container component for managing arrays of child elements
496
+ *
497
+ * Features:
498
+ * 1. Returns a comment anchor node, child elements are inserted after the anchor
499
+ * 2. Supports reactive arrays, automatically updates DOM when array changes
500
+ * 3. Basic version uses simple replacement algorithm (remove all old elements, insert all new elements)
501
+ * 4. Future enhancement: key-based optimization
502
+ *
503
+ * Usage example:
504
+ * ```tsx
505
+ * const children = ref([<div>A</div>, <div>B</div>]);
506
+ * const fragment = <Fragment children={children} />;
507
+ * document.body.appendChild(fragment);
508
+ *
509
+ * // Automatic update
510
+ * children.value = [<div>C</div>, <div>D</div>];
511
+ * ```
512
+ */
513
+ function Fragment$1(props) {
514
+ // key parameter reserved for future enhancement, currently unused
515
+ const { key: _key } = props;
516
+ const childrenRef = toReactive(props.children, () => anchor.kredraw());
517
+ const anchor = document.createComment('kt-fragment');
518
+ anchor.kredraw = kredraw;
519
+ anchor.kchildrenRef = childrenRef;
520
+ anchor.kFragmentList = [];
521
+ anchor.kisFragmentAnchor = true;
522
+ // Observe DOM insertion
523
+ const observer = new MutationObserver(() => {
524
+ if (anchor.isConnected) {
525
+ anchor.kredraw();
526
+ observer.disconnect();
527
+ }
528
+ });
529
+ observer.observe(document.body, { childList: true, subtree: true });
530
+ // Set ref reference
531
+ $setRef(props, anchor);
532
+ return anchor;
533
+ }
534
+ /**
535
+ * Convert KTRawContent to HTMLElement array
536
+ */
537
+ function convertChildrenToElements(children) {
538
+ const elements = [];
539
+ const processChild = (child) => {
540
+ if (child == null || child === false || child === true) {
541
+ // Ignore null, undefined, false, true
542
+ return;
543
+ }
544
+ if ($isArray(child)) {
545
+ // Recursively process array
546
+ $forEach(child, processChild);
547
+ return;
548
+ }
549
+ if (typeof child === 'string' || typeof child === 'number') {
550
+ // & Wrap text in span element? No! use text node instead
551
+ const textNode = document.createTextNode(String(child));
552
+ elements.push(textNode);
553
+ return;
554
+ }
555
+ if (child instanceof HTMLElement) {
556
+ elements.push(child);
557
+ return;
558
+ }
559
+ if (isKT(child)) {
560
+ processChild(child.value);
561
+ return;
562
+ }
563
+ // Other types ignored or converted to string
564
+ console.warn('[kt.js warn]','Fragment: unsupported child type', child);
565
+ };
566
+ processChild(children);
567
+ return elements;
568
+ }
569
+
420
570
  const create = (tag, props) => {
421
571
  if (typeof tag === 'function') {
422
572
  return tag(props);
@@ -434,7 +584,6 @@ function jsx(tag, props) {
434
584
  if (isComputed(props.ref)) {
435
585
  throw new Error('[kt.js error] Cannot assign a computed value to an element.');
436
586
  }
437
- const maybeDummyRef = isRef(props.ref) ? props.ref : dummyRef;
438
587
  let el;
439
588
  if ('k-if' in props) {
440
589
  const kif = props['k-if'];
@@ -446,49 +595,31 @@ function jsx(tag, props) {
446
595
  return;
447
596
  }
448
597
  const oldEl = el;
449
- el = newValue ? create(tag, props) : placeholder();
598
+ $setRef(props, (el = newValue ? create(tag, props) : placeholder()));
450
599
  $replaceNode(oldEl, el);
451
- maybeDummyRef.value = el;
452
600
  });
453
601
  condition = kif.value;
454
602
  }
455
603
  if (!condition) {
456
604
  // & make comment placeholder in case that ref might be redrawn later
457
- el = placeholder();
458
- maybeDummyRef.value = el;
605
+ $setRef(props, (el = placeholder()));
459
606
  return el;
460
607
  }
461
608
  }
462
- el = create(tag, props);
463
- maybeDummyRef.value = el;
609
+ $setRef(props, (el = create(tag, props)));
464
610
  return el;
465
611
  }
466
612
  /**
467
613
  * Fragment support - returns an array of children
468
- * Note: kt.js doesn't have a real Fragment concept,
614
+ * Enhanced Fragment component that manages arrays of elements
469
615
  */
470
- function Fragment(_props) {
471
- throw new Error("[kt.js error] doesn't have a Fragment concept");
472
- // const { children } = props ?? {};
473
- // if (!children) {
474
- // return ;
475
- // }
476
- // // If single child, return it directly
477
- // if (!Array.isArray(children)) {
478
- // return children as HTMLElement;
479
- // }
480
- // // For multiple children, create a document fragment wrapper
481
- // // This is a limitation - JSX fragments must be wrapped in kt.js
482
- // const wrapper = document.createElement('div');
483
- // wrapper.setAttribute('data-kt-fragment', 'true');
484
- // children.forEach((child) => {
485
- // if (typeof child === 'string') {
486
- // wrapper.appendChild(document.createTextNode(child));
487
- // } else if (child instanceof HTMLElement) {
488
- // wrapper.appendChild(child);
489
- // }
490
- // });
491
- // return wrapper;
616
+ function Fragment(props) {
617
+ const { children } = props ?? {};
618
+ if (!children) {
619
+ return document.createComment('kt-fragment-empty');
620
+ }
621
+ const elements = convertChildrenToElements(children);
622
+ return Fragment$1({ children: elements });
492
623
  }
493
624
  /**
494
625
  * JSX Development runtime - same as jsx but with additional dev checks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.26.9",
3
+ "version": "0.27.2",
4
4
  "description": "Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -44,7 +44,7 @@
44
44
  "directory": "packages/core"
45
45
  },
46
46
  "dependencies": {
47
- "@ktjs/shared": "0.23.3"
47
+ "@ktjs/shared": "0.23.10"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "rollup -c rollup.config.mjs",