@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.
- package/dist/index.d.ts +10 -9
- package/dist/index.iife.js +203 -103
- package/dist/index.legacy.js +203 -105
- package/dist/index.mjs +203 -104
- package/dist/jsx/index.d.ts +4 -4
- package/dist/jsx/index.mjs +183 -52
- package/dist/jsx/jsx-runtime.d.ts +4 -4
- package/dist/jsx/jsx-runtime.mjs +183 -52
- package/package.json +2 -2
package/dist/jsx/index.mjs
CHANGED
|
@@ -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
|
-
|
|
78
|
-
|
|
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.
|
|
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
|
|
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
|
-
*
|
|
614
|
+
* Enhanced Fragment component that manages arrays of elements
|
|
469
615
|
*/
|
|
470
|
-
function Fragment(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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.
|
|
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
|
-
*
|
|
154
|
+
* Enhanced Fragment component that manages arrays of elements
|
|
155
155
|
*/
|
|
156
|
-
declare function Fragment(
|
|
156
|
+
declare function Fragment(props: {
|
|
157
157
|
children?: KTRawContent;
|
|
158
|
-
}):
|
|
158
|
+
}): JSX.Element;
|
|
159
159
|
/**
|
|
160
160
|
* JSX Development runtime - same as jsx but with additional dev checks
|
|
161
161
|
*/
|
package/dist/jsx/jsx-runtime.mjs
CHANGED
|
@@ -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
|
-
|
|
78
|
-
|
|
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.
|
|
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
|
|
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
|
-
*
|
|
614
|
+
* Enhanced Fragment component that manages arrays of elements
|
|
469
615
|
*/
|
|
470
|
-
function Fragment(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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.
|
|
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.
|
|
47
|
+
"@ktjs/shared": "0.23.10"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "rollup -c rollup.config.mjs",
|