@ktjs/core 0.27.2 → 0.28.1

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.
@@ -14,29 +14,6 @@ var __ktjs_core__ = (function (exports) {
14
14
  };
15
15
  }
16
16
 
17
- // String manipulation utilities
18
- /**
19
- * Default empty function
20
- */
21
- const $emptyFn = (() => true);
22
- const $emptyArray = [];
23
- /**
24
- * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
25
- */
26
- const $forEach = (array, callback) => {
27
- const len = array.length;
28
- for (let i = 0; i < len; i++) {
29
- callback(array[i], i, array);
30
- }
31
- };
32
-
33
- const $emptyChildrenRef = { value: $emptyArray };
34
- // each instance shares the same empty array, but it will be replaced when used
35
- Comment.prototype.kisFragmentAnchor = false;
36
- Comment.prototype.kFragmentList = $emptyArray;
37
- Comment.prototype.kredraw = $emptyFn;
38
- Comment.prototype.kchildrenRef = $emptyChildrenRef;
39
-
40
17
  // Shared constants
41
18
  // Empty for now - can be extended with framework-wide constants
42
19
  /**
@@ -107,8 +84,23 @@ var __ktjs_core__ = (function (exports) {
107
84
  element.addEventListener(eventName, () => (valueRef.value = element[propName]));
108
85
  };
109
86
 
87
+ // String manipulation utilities
88
+ /**
89
+ * Default empty function
90
+ */
91
+ const $emptyFn = (() => true);
92
+ /**
93
+ * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
94
+ */
95
+ const $forEach = (array, callback) => {
96
+ const len = array.length;
97
+ for (let i = 0; i < len; i++) {
98
+ callback(array[i], i, array);
99
+ }
100
+ };
101
+
110
102
  // incase that symbol is not supported
111
- Object.defineProperty(window, '__ktjs__', { value: '0.23.10' });
103
+ Object.defineProperty(window, '__ktjs__', { value: '0.23.11' });
112
104
 
113
105
  var isKT = function (obj) { return obj === null || obj === void 0 ? void 0 : obj.isKT; };
114
106
  var isRef = function (obj) { return (obj === null || obj === void 0 ? void 0 : obj.ktType) === 1 /* KTReactiveType.REF */; };
@@ -323,6 +315,14 @@ var __ktjs_core__ = (function (exports) {
323
315
  this._value = _value;
324
316
  this._onChanges = _onChanges;
325
317
  }
318
+ /**
319
+ * @internal
320
+ */
321
+ KTRef.prototype._emit = function (newValue, oldValue) {
322
+ for (var i = 0; i < this._onChanges.length; i++) {
323
+ this._onChanges[i](newValue, oldValue);
324
+ }
325
+ };
326
326
  Object.defineProperty(KTRef.prototype, "value", {
327
327
  /**
328
328
  * If new value and old value are both nodes, the old one will be replaced in the DOM
@@ -337,13 +337,34 @@ var __ktjs_core__ = (function (exports) {
337
337
  var oldValue = this._value;
338
338
  $replaceNode(oldValue, newValue);
339
339
  this._value = newValue;
340
- for (var i = 0; i < this._onChanges.length; i++) {
341
- this._onChanges[i](newValue, oldValue);
342
- }
340
+ this._emit(newValue, oldValue);
343
341
  },
344
342
  enumerable: false,
345
343
  configurable: true
346
344
  });
345
+ /**
346
+ * Force all listeners to run even when reference identity has not changed.
347
+ * Useful for in-place array/object mutations.
348
+ */
349
+ KTRef.prototype.notify = function () {
350
+ this._emit(this._value, this._value);
351
+ };
352
+ /**
353
+ * Mutate current value in-place and notify listeners once.
354
+ *
355
+ * @example
356
+ * const items = ref<number[]>([1, 2]);
357
+ * items.mutate((list) => list.push(3));
358
+ */
359
+ KTRef.prototype.mutate = function (mutator) {
360
+ if (typeof mutator !== 'function') {
361
+ throw new Error('[kt.js error] KTRef.mutate: mutator must be a function');
362
+ }
363
+ var oldValue = this._value;
364
+ var result = mutator(this._value);
365
+ this._emit(this._value, oldValue);
366
+ return result;
367
+ };
347
368
  /**
348
369
  * Register a callback when the value changes
349
370
  * @param callback (newValue, oldValue) => xxx
@@ -393,9 +414,6 @@ var __ktjs_core__ = (function (exports) {
393
414
  return ref(o);
394
415
  }
395
416
  };
396
- function deref(value) {
397
- return isKT(value) ? value.value : value;
398
- }
399
417
  function kcollect() {
400
418
  var newObj = {};
401
419
  var entries = $entries(this);
@@ -464,6 +482,31 @@ var __ktjs_core__ = (function (exports) {
464
482
  this._value = _calculator();
465
483
  this._subscribe(reactives);
466
484
  }
485
+ /**
486
+ * @internal
487
+ */
488
+ KTComputed.prototype._emit = function (newValue, oldValue) {
489
+ for (var i = 0; i < this._onChanges.length; i++) {
490
+ this._onChanges[i](newValue, oldValue);
491
+ }
492
+ };
493
+ /**
494
+ * @internal
495
+ */
496
+ KTComputed.prototype._recalculate = function (forceEmit) {
497
+ if (forceEmit === void 0) { forceEmit = false; }
498
+ var oldValue = this._value;
499
+ var newValue = this._calculator();
500
+ if (oldValue === newValue) {
501
+ if (forceEmit) {
502
+ this._emit(newValue, oldValue);
503
+ }
504
+ return;
505
+ }
506
+ this._value = newValue;
507
+ $replaceNode(oldValue, newValue);
508
+ this._emit(newValue, oldValue);
509
+ };
467
510
  /**
468
511
  * @internal
469
512
  */
@@ -471,17 +514,7 @@ var __ktjs_core__ = (function (exports) {
471
514
  var _this = this;
472
515
  for (var i = 0; i < reactives.length; i++) {
473
516
  var reactive = reactives[i];
474
- reactive.addOnChange(function () {
475
- var oldValue = _this._value;
476
- _this._value = _this._calculator();
477
- if (oldValue === _this._value) {
478
- return;
479
- }
480
- $replaceNode(oldValue, _this._value);
481
- for (var i_1 = 0; i_1 < _this._onChanges.length; i_1++) {
482
- _this._onChanges[i_1](_this._value, oldValue);
483
- }
484
- });
517
+ reactive.addOnChange(function () { return _this._recalculate(); });
485
518
  }
486
519
  };
487
520
  Object.defineProperty(KTComputed.prototype, "value", {
@@ -497,6 +530,18 @@ var __ktjs_core__ = (function (exports) {
497
530
  enumerable: false,
498
531
  configurable: true
499
532
  });
533
+ /**
534
+ * Force listeners to run once with the latest computed result.
535
+ */
536
+ KTComputed.prototype.notify = function () {
537
+ this._recalculate(true);
538
+ };
539
+ /**
540
+ * Computed values are derived from dependencies and should not be mutated manually.
541
+ */
542
+ KTComputed.prototype.mutate = function (_mutator) {
543
+ console.warn('[kt.js warn]','KTComputed.mutate: computed is derived automatically; manual mutate is ignored. Use notify() instead');
544
+ };
500
545
  /**
501
546
  * Register a callback when the value changes
502
547
  * @param callback (newValue, oldValue) => xxx
@@ -590,6 +635,12 @@ var __ktjs_core__ = (function (exports) {
590
635
  return ref(value, onChange);
591
636
  }
592
637
  };
638
+ /**
639
+ * Extracts the value from a KTReactive, or returns the value directly if it's not reactive.
640
+ */
641
+ function dereactive(value) {
642
+ return isKT(value) ? value.value : value;
643
+ }
593
644
 
594
645
  function applyKModel(element, valueRef) {
595
646
  if (!isKT(valueRef)) {
@@ -629,7 +680,7 @@ var __ktjs_core__ = (function (exports) {
629
680
  * ## About
630
681
  * @package @ktjs/core
631
682
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
632
- * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
683
+ * @version 0.28.1 (Last Update: 2026.02.10 11:23:01.128)
633
684
  * @license MIT
634
685
  * @link https://github.com/baendlorel/kt.js
635
686
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -664,34 +715,6 @@ var __ktjs_core__ = (function (exports) {
664
715
  return element;
665
716
  };
666
717
 
667
- var kredraw = function () {
668
- var newElements = this.kchildrenRef.value;
669
- var parent = this.parentNode;
670
- if (!parent) {
671
- // If anchor is not in DOM, only update internal state
672
- this.kFragmentList.length = 0;
673
- for (var i = 0; i < newElements.length; i++) {
674
- this.kFragmentList.push(newElements[i]);
675
- }
676
- return;
677
- }
678
- // Simple replacement algorithm: remove all old elements, insert all new elements
679
- // todo Future enhancement: key-based optimization
680
- // 1. Remove all old elements
681
- for (var i = 0; i < this.kFragmentList.length; i++) {
682
- this.kFragmentList[i].remove();
683
- }
684
- // 2. Insert all new elements
685
- var fragment = document.createDocumentFragment();
686
- this.kFragmentList.length = 0;
687
- for (var i = 0; i < newElements.length; i++) {
688
- var element = newElements[i];
689
- this.kFragmentList.push(element);
690
- fragment.appendChild(element);
691
- }
692
- // Insert after anchor
693
- parent.insertBefore(fragment, this.nextSibling);
694
- };
695
718
  /**
696
719
  * Fragment - Container component for managing arrays of child elements
697
720
  *
@@ -713,17 +736,44 @@ var __ktjs_core__ = (function (exports) {
713
736
  */
714
737
  function Fragment$1(props) {
715
738
  // key parameter reserved for future enhancement, currently unused
716
- props.key;
717
- var childrenRef = toReactive(props.children, function () { return anchor.kredraw(); });
739
+ // const { key: _key } = props;
740
+ var redraw = function () {
741
+ var newElements = childrenRef.value;
742
+ var parent = anchor.parentNode;
743
+ if (!parent) {
744
+ // If anchor is not in DOM, only update internal state
745
+ elements.length = 0;
746
+ for (var i = 0; i < newElements.length; i++) {
747
+ elements.push(newElements[i]);
748
+ }
749
+ return;
750
+ }
751
+ // Simple replacement algorithm: remove all old elements, insert all new elements
752
+ // todo Future enhancement: key-based optimization
753
+ // 1. Remove all old elements
754
+ for (var i = 0; i < elements.length; i++) {
755
+ elements[i].remove();
756
+ }
757
+ // 2. Insert all new elements
758
+ var fragment = document.createDocumentFragment();
759
+ elements.length = 0;
760
+ for (var i = 0; i < newElements.length; i++) {
761
+ var element = newElements[i];
762
+ elements.push(element);
763
+ fragment.appendChild(element);
764
+ }
765
+ // Insert after anchor
766
+ parent.insertBefore(fragment, anchor.nextSibling);
767
+ };
768
+ var initialized = false;
769
+ var childrenRef = toReactive(props.children, redraw);
770
+ var elements = [];
718
771
  var anchor = document.createComment('kt-fragment');
719
- anchor.kredraw = kredraw;
720
- anchor.kchildrenRef = childrenRef;
721
- anchor.kFragmentList = [];
722
- anchor.kisFragmentAnchor = true;
723
772
  // Observe DOM insertion
724
773
  var observer = new MutationObserver(function () {
725
- if (anchor.isConnected) {
726
- anchor.kredraw();
774
+ if (anchor.isConnected && !initialized) {
775
+ initialized = true;
776
+ redraw();
727
777
  observer.disconnect();
728
778
  }
729
779
  });
@@ -1083,7 +1133,7 @@ var __ktjs_core__ = (function (exports) {
1083
1133
  exports.computed = computed;
1084
1134
  exports.createElement = h;
1085
1135
  exports.createRedrawable = createRedrawable;
1086
- exports.deref = deref;
1136
+ exports.dereactive = dereactive;
1087
1137
  exports.effect = effect;
1088
1138
  exports.h = h;
1089
1139
  exports.isComputed = isComputed;
package/dist/index.mjs CHANGED
@@ -11,29 +11,6 @@ if (typeof Symbol === 'undefined') {
11
11
  };
12
12
  }
13
13
 
14
- // String manipulation utilities
15
- /**
16
- * Default empty function
17
- */
18
- const $emptyFn = (() => true);
19
- const $emptyArray = [];
20
- /**
21
- * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
22
- */
23
- const $forEach = (array, callback) => {
24
- const len = array.length;
25
- for (let i = 0; i < len; i++) {
26
- callback(array[i], i, array);
27
- }
28
- };
29
-
30
- const $emptyChildrenRef = { value: $emptyArray };
31
- // each instance shares the same empty array, but it will be replaced when used
32
- Comment.prototype.kisFragmentAnchor = false;
33
- Comment.prototype.kFragmentList = $emptyArray;
34
- Comment.prototype.kredraw = $emptyFn;
35
- Comment.prototype.kchildrenRef = $emptyChildrenRef;
36
-
37
14
  // Shared constants
38
15
  // Empty for now - can be extended with framework-wide constants
39
16
  /**
@@ -104,8 +81,23 @@ const $applyModel = (element, valueRef, propName, eventName) => {
104
81
  element.addEventListener(eventName, () => (valueRef.value = element[propName]));
105
82
  };
106
83
 
84
+ // String manipulation utilities
85
+ /**
86
+ * Default empty function
87
+ */
88
+ const $emptyFn = (() => true);
89
+ /**
90
+ * Safe and quick forEach implementation that works with array-like objects and handles sparse arrays.
91
+ */
92
+ const $forEach = (array, callback) => {
93
+ const len = array.length;
94
+ for (let i = 0; i < len; i++) {
95
+ callback(array[i], i, array);
96
+ }
97
+ };
98
+
107
99
  // incase that symbol is not supported
108
- Object.defineProperty(window, '__ktjs__', { value: '0.23.10' });
100
+ Object.defineProperty(window, '__ktjs__', { value: '0.23.11' });
109
101
 
110
102
  const isKT = (obj) => obj?.isKT;
111
103
  const isRef = (obj) => obj?.ktType === 1 /* KTReactiveType.REF */;
@@ -316,6 +308,14 @@ class KTRef {
316
308
  * @internal
317
309
  */
318
310
  _onChanges;
311
+ /**
312
+ * @internal
313
+ */
314
+ _emit(newValue, oldValue) {
315
+ for (let i = 0; i < this._onChanges.length; i++) {
316
+ this._onChanges[i](newValue, oldValue);
317
+ }
318
+ }
319
319
  constructor(_value, _onChanges) {
320
320
  this._value = _value;
321
321
  this._onChanges = _onChanges;
@@ -333,9 +333,30 @@ class KTRef {
333
333
  const oldValue = this._value;
334
334
  $replaceNode(oldValue, newValue);
335
335
  this._value = newValue;
336
- for (let i = 0; i < this._onChanges.length; i++) {
337
- this._onChanges[i](newValue, oldValue);
336
+ this._emit(newValue, oldValue);
337
+ }
338
+ /**
339
+ * Force all listeners to run even when reference identity has not changed.
340
+ * Useful for in-place array/object mutations.
341
+ */
342
+ notify() {
343
+ this._emit(this._value, this._value);
344
+ }
345
+ /**
346
+ * Mutate current value in-place and notify listeners once.
347
+ *
348
+ * @example
349
+ * const items = ref<number[]>([1, 2]);
350
+ * items.mutate((list) => list.push(3));
351
+ */
352
+ mutate(mutator) {
353
+ if (typeof mutator !== 'function') {
354
+ throw new Error('[kt.js error] KTRef.mutate: mutator must be a function');
338
355
  }
356
+ const oldValue = this._value;
357
+ const result = mutator(this._value);
358
+ this._emit(this._value, oldValue);
359
+ return result;
339
360
  }
340
361
  /**
341
362
  * Register a callback when the value changes
@@ -385,9 +406,6 @@ const toRef = (o) => {
385
406
  return ref(o);
386
407
  }
387
408
  };
388
- function deref(value) {
389
- return isKT(value) ? value.value : value;
390
- }
391
409
  function kcollect() {
392
410
  const newObj = {};
393
411
  const entries = $entries(this);
@@ -459,23 +477,37 @@ class KTComputed {
459
477
  * @internal
460
478
  */
461
479
  _onChanges = [];
480
+ /**
481
+ * @internal
482
+ */
483
+ _emit(newValue, oldValue) {
484
+ for (let i = 0; i < this._onChanges.length; i++) {
485
+ this._onChanges[i](newValue, oldValue);
486
+ }
487
+ }
488
+ /**
489
+ * @internal
490
+ */
491
+ _recalculate(forceEmit = false) {
492
+ const oldValue = this._value;
493
+ const newValue = this._calculator();
494
+ if (oldValue === newValue) {
495
+ if (forceEmit) {
496
+ this._emit(newValue, oldValue);
497
+ }
498
+ return;
499
+ }
500
+ this._value = newValue;
501
+ $replaceNode(oldValue, newValue);
502
+ this._emit(newValue, oldValue);
503
+ }
462
504
  /**
463
505
  * @internal
464
506
  */
465
507
  _subscribe(reactives) {
466
508
  for (let i = 0; i < reactives.length; i++) {
467
509
  const reactive = reactives[i];
468
- reactive.addOnChange(() => {
469
- const oldValue = this._value;
470
- this._value = this._calculator();
471
- if (oldValue === this._value) {
472
- return;
473
- }
474
- $replaceNode(oldValue, this._value);
475
- for (let i = 0; i < this._onChanges.length; i++) {
476
- this._onChanges[i](this._value, oldValue);
477
- }
478
- });
510
+ reactive.addOnChange(() => this._recalculate());
479
511
  }
480
512
  }
481
513
  constructor(_calculator, reactives) {
@@ -492,6 +524,18 @@ class KTComputed {
492
524
  set value(_newValue) {
493
525
  throw new Error('[kt.js error] KTComputed: cannot set value of a computed value');
494
526
  }
527
+ /**
528
+ * Force listeners to run once with the latest computed result.
529
+ */
530
+ notify() {
531
+ this._recalculate(true);
532
+ }
533
+ /**
534
+ * Computed values are derived from dependencies and should not be mutated manually.
535
+ */
536
+ mutate(_mutator) {
537
+ console.warn('[kt.js warn]','KTComputed.mutate: computed is derived automatically; manual mutate is ignored. Use notify() instead');
538
+ }
495
539
  /**
496
540
  * Register a callback when the value changes
497
541
  * @param callback (newValue, oldValue) => xxx
@@ -584,6 +628,12 @@ const toReactive = (value, onChange) => {
584
628
  return ref(value, onChange);
585
629
  }
586
630
  };
631
+ /**
632
+ * Extracts the value from a KTReactive, or returns the value directly if it's not reactive.
633
+ */
634
+ function dereactive(value) {
635
+ return isKT(value) ? value.value : value;
636
+ }
587
637
 
588
638
  function applyKModel(element, valueRef) {
589
639
  if (!isKT(valueRef)) {
@@ -623,7 +673,7 @@ let creator = htmlCreator;
623
673
  * ## About
624
674
  * @package @ktjs/core
625
675
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
626
- * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
676
+ * @version 0.28.1 (Last Update: 2026.02.10 11:23:01.128)
627
677
  * @license MIT
628
678
  * @link https://github.com/baendlorel/kt.js
629
679
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -658,34 +708,6 @@ const h = (tag, attr, content) => {
658
708
  return element;
659
709
  };
660
710
 
661
- const kredraw = function () {
662
- const newElements = this.kchildrenRef.value;
663
- const parent = this.parentNode;
664
- if (!parent) {
665
- // If anchor is not in DOM, only update internal state
666
- this.kFragmentList.length = 0;
667
- for (let i = 0; i < newElements.length; i++) {
668
- this.kFragmentList.push(newElements[i]);
669
- }
670
- return;
671
- }
672
- // Simple replacement algorithm: remove all old elements, insert all new elements
673
- // todo Future enhancement: key-based optimization
674
- // 1. Remove all old elements
675
- for (let i = 0; i < this.kFragmentList.length; i++) {
676
- this.kFragmentList[i].remove();
677
- }
678
- // 2. Insert all new elements
679
- const fragment = document.createDocumentFragment();
680
- this.kFragmentList.length = 0;
681
- for (let i = 0; i < newElements.length; i++) {
682
- const element = newElements[i];
683
- this.kFragmentList.push(element);
684
- fragment.appendChild(element);
685
- }
686
- // Insert after anchor
687
- parent.insertBefore(fragment, this.nextSibling);
688
- };
689
711
  /**
690
712
  * Fragment - Container component for managing arrays of child elements
691
713
  *
@@ -707,17 +729,44 @@ const kredraw = function () {
707
729
  */
708
730
  function Fragment$1(props) {
709
731
  // key parameter reserved for future enhancement, currently unused
710
- const { key: _key } = props;
711
- const childrenRef = toReactive(props.children, () => anchor.kredraw());
732
+ // const { key: _key } = props;
733
+ const redraw = () => {
734
+ const newElements = childrenRef.value;
735
+ const parent = anchor.parentNode;
736
+ if (!parent) {
737
+ // If anchor is not in DOM, only update internal state
738
+ elements.length = 0;
739
+ for (let i = 0; i < newElements.length; i++) {
740
+ elements.push(newElements[i]);
741
+ }
742
+ return;
743
+ }
744
+ // Simple replacement algorithm: remove all old elements, insert all new elements
745
+ // todo Future enhancement: key-based optimization
746
+ // 1. Remove all old elements
747
+ for (let i = 0; i < elements.length; i++) {
748
+ elements[i].remove();
749
+ }
750
+ // 2. Insert all new elements
751
+ const fragment = document.createDocumentFragment();
752
+ elements.length = 0;
753
+ for (let i = 0; i < newElements.length; i++) {
754
+ const element = newElements[i];
755
+ elements.push(element);
756
+ fragment.appendChild(element);
757
+ }
758
+ // Insert after anchor
759
+ parent.insertBefore(fragment, anchor.nextSibling);
760
+ };
761
+ let initialized = false;
762
+ const childrenRef = toReactive(props.children, redraw);
763
+ const elements = [];
712
764
  const anchor = document.createComment('kt-fragment');
713
- anchor.kredraw = kredraw;
714
- anchor.kchildrenRef = childrenRef;
715
- anchor.kFragmentList = [];
716
- anchor.kisFragmentAnchor = true;
717
765
  // Observe DOM insertion
718
766
  const observer = new MutationObserver(() => {
719
- if (anchor.isConnected) {
720
- anchor.kredraw();
767
+ if (anchor.isConnected && !initialized) {
768
+ initialized = true;
769
+ redraw();
721
770
  observer.disconnect();
722
771
  }
723
772
  });
@@ -1062,4 +1111,4 @@ function getSequence(arr) {
1062
1111
  return result;
1063
1112
  }
1064
1113
 
1065
- export { $modelOrRef, $setRef, Fragment, KTAsync, KTComputed, KTFor, KTRef, computed, h as createElement, createRedrawable, deref, effect, h, isComputed, isKT, isRef, jsx, jsxDEV, jsxs, ref, surfaceRef, toReactive, toRef };
1114
+ export { $modelOrRef, $setRef, Fragment, KTAsync, KTComputed, KTFor, KTRef, computed, h as createElement, createRedrawable, dereactive, effect, h, isComputed, isKT, isRef, jsx, jsxDEV, jsxs, ref, surfaceRef, toReactive, toRef };
@@ -1,30 +1,5 @@
1
1
  import { otherstring, HTMLTag, SVGTag, MathMLTag } from '@ktjs/shared';
2
2
 
3
- declare class KTComputed<T> {
4
- /**
5
- * Indicates that this is a KTRef instance
6
- */
7
- isKT: true;
8
- ktType: KTReactiveType;
9
- constructor(_calculator: () => T, reactives: Array<KTReactive<unknown>>);
10
- /**
11
- * If new value and old value are both nodes, the old one will be replaced in the DOM
12
- */
13
- get value(): T;
14
- set value(_newValue: T);
15
- /**
16
- * Register a callback when the value changes
17
- * @param callback (newValue, oldValue) => xxx
18
- */
19
- addOnChange(callback: ReactiveChangeHandler<T>): void;
20
- /**
21
- * Unregister a callback
22
- * @param callback (newValue, oldValue) => xxx
23
- */
24
- removeOnChange(callback: ReactiveChangeHandler<T>): boolean;
25
- }
26
-
27
- type KTReactive<T> = KTRef<T> | KTComputed<T>;
28
3
  type KTReactify<T> = T extends boolean ? KTReactive<boolean> : T extends any ? KTReactive<T> : never;
29
4
  type KTReactifyProps<T extends object> = {
30
5
  [K in keyof T]: KTReactify<Exclude<T[K], undefined>> | T[K];
@@ -34,8 +9,45 @@ declare const enum KTReactiveType {
34
9
  REF = 1,
35
10
  COMPUTED = 2
36
11
  }
12
+
37
13
  type ReactiveChangeHandler<T> = (newValue: T, oldValue: T) => void;
38
14
 
15
+ declare class KTReactive<T> {
16
+ /**
17
+ * Indicates that this is a KTRef instance
18
+ */
19
+ isKT: boolean;
20
+
21
+ ktType: KTReactiveType;
22
+
23
+ /**
24
+ * If new value and old value are both nodes, the old one will be replaced in the DOM
25
+ */
26
+ get value();
27
+ set value(newValue: T);
28
+
29
+ /**
30
+ * Force all listeners to run even when reference identity has not changed.
31
+ * Useful for in-place array/object mutations.
32
+ */
33
+ notify(): void;
34
+
35
+ /**
36
+ * Mutate current value in-place and notify listeners once.
37
+ *
38
+ * @example
39
+ * const items = ref<number[]>([1, 2]);
40
+ * items.mutate((list) => list.push(3));
41
+ */
42
+ mutate<R = void>(mutator: (currentValue: T) => R): R;
43
+ /**
44
+ * Register a callback when the value changes
45
+ * @param callback (newValue, oldValue) => xxx
46
+ */
47
+ addOnChange(callback: ReactiveChangeHandler<T>): void;
48
+ removeOnChange(callback: ReactiveChangeHandler<T>): void;
49
+ }
50
+
39
51
  declare class KTRef<T> {
40
52
  /**
41
53
  * Indicates that this is a KTRef instance
@@ -48,6 +60,19 @@ declare class KTRef<T> {
48
60
  */
49
61
  get value(): T;
50
62
  set value(newValue: T);
63
+ /**
64
+ * Force all listeners to run even when reference identity has not changed.
65
+ * Useful for in-place array/object mutations.
66
+ */
67
+ notify(): void;
68
+ /**
69
+ * Mutate current value in-place and notify listeners once.
70
+ *
71
+ * @example
72
+ * const items = ref<number[]>([1, 2]);
73
+ * items.mutate((list) => list.push(3));
74
+ */
75
+ mutate<R = void>(mutator: (currentValue: T) => R): R;
51
76
  /**
52
77
  * Register a callback when the value changes
53
78
  * @param callback (newValue, oldValue) => xxx
@@ -164,7 +189,7 @@ type KTAttribute = KTBaseAttribute & KTPrefixedEventAttribute;
164
189
  * ## About
165
190
  * @package @ktjs/core
166
191
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
167
- * @version 0.27.2 (Last Update: 2026.02.10 07:27:25.966)
192
+ * @version 0.28.1 (Last Update: 2026.02.10 11:23:01.128)
168
193
  * @license MIT
169
194
  * @link https://github.com/baendlorel/kt.js
170
195
  * @link https://baendlorel.github.io/ Welcome to my site!