@ktjs/core 0.23.0 → 0.24.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.
@@ -1,14 +1,38 @@
1
1
  var __ktjs_core__ = (function (exports) {
2
2
  'use strict';
3
3
 
4
+ // Shared constants
5
+ // Empty for now - can be extended with framework-wide constants
6
+ /**
7
+ * Mark the attribute as SVG to handle special cases during rendering.
8
+ */
9
+ const SVG_ATTR_FLAG = '__kt_svg__';
10
+ /**
11
+ * Mark the attribute as MathML to handle special cases during rendering.
12
+ */
13
+ const MATHML_ATTR_FLAG = '__kt_mathml__';
14
+
4
15
  // Cached native methods for performance optimization
5
16
  const $isArray = Array.isArray;
17
+ const $is = Object.is;
6
18
  const $entries = Object.entries;
7
- const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
19
+ const $random = Math.random;
20
+ const $isThenable = (o) => typeof o?.then === 'function';
8
21
 
9
22
  // DOM manipulation utilities
10
23
  // # dom natives
11
24
  const $isNode = (x) => x?.nodeType > 0;
25
+ /**
26
+ * Safe replace `oldNode` With `newNode`
27
+ */
28
+ const $replaceNode = (oldNode, newNode) => {
29
+ if ($isNode(oldNode) && $isNode(newNode)) {
30
+ if (newNode.contains(oldNode)) {
31
+ newNode.remove();
32
+ }
33
+ oldNode.replaceWith(newNode);
34
+ }
35
+ };
12
36
  /**
13
37
  * & Remove `bind` because it is shockingly slower than wrapper
14
38
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -54,130 +78,21 @@ var __ktjs_core__ = (function (exports) {
54
78
  element.addEventListener(eventName, () => (valueRef.value = element[propName]));
55
79
  };
56
80
 
81
+ if (typeof Symbol === 'undefined') {
82
+ window.Symbol = function Symbol(description) {
83
+ return `@@SYMBOL_${description || ''}_${$random().toString(36).slice(2)}`;
84
+ };
85
+ }
86
+
57
87
  // Shared utilities and cached native methods for kt.js framework
58
- // import './misc/symbol-polyfill.js';
59
- // Re-export all utilities
60
- Object.defineProperty(window, '__ktjs__', { value: '0.22.3' });
88
+ Object.defineProperty(window, '__ktjs__', { value: '0.22.6' });
61
89
 
62
- class KTRef {
63
- /**
64
- * Indicates that this is a KTRef instance
65
- */
66
- isKT = true;
67
- /**
68
- * @internal
69
- */
70
- _value;
71
- /**
72
- * @internal
73
- */
74
- _onChanges;
75
- constructor(_value, _onChanges) {
76
- this._value = _value;
77
- this._onChanges = _onChanges;
78
- }
79
- /**
80
- * If new value and old value are both nodes, the old one will be replaced in the DOM
81
- */
82
- get value() {
83
- return this._value;
84
- }
85
- set value(newValue) {
86
- if (newValue === this._value) {
87
- return;
88
- }
89
- // replace the old node with the new one in the DOM if both are nodes
90
- if (this._value instanceof Node && newValue instanceof Node) {
91
- if (newValue.contains(this._value)) {
92
- this._value.remove();
93
- }
94
- this._value.replaceWith(newValue);
95
- }
96
- const oldValue = this._value;
97
- this._value = newValue;
98
- for (let i = 0; i < this._onChanges.length; i++) {
99
- this._onChanges[i](newValue, oldValue);
100
- }
101
- }
102
- /**
103
- * Register a callback when the value changes
104
- * @param callback (newValue, oldValue) => xxx
105
- */
106
- addOnChange(callback) {
107
- if (typeof callback !== 'function') {
108
- throw new Error('[kt.js error] KTRef.addOnChange: callback must be a function');
109
- }
110
- this._onChanges.push(callback);
111
- }
112
- removeOnChange(callback) {
113
- for (let i = this._onChanges.length - 1; i >= 0; i--) {
114
- if (this._onChanges[i] === callback) {
115
- this._onChanges.splice(i, 1);
116
- return true;
117
- }
118
- }
119
- return false;
120
- }
121
- }
122
- const isKTRef = (obj) => obj?.isKT === true;
123
- /**
124
- * Reference to the created HTML element.
125
- * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
126
- * - can alse be used to store normal values, but it is not reactive.
127
- * - if the value is already a `KTRef`, it will be returned **directly**.
128
- * @param value mostly an HTMLElement
129
- */
130
- function ref(value, onChange) {
131
- if (isKTRef(value)) {
132
- if (onChange) {
133
- value.addOnChange(onChange);
134
- }
135
- return value;
136
- }
137
- return new KTRef(value, onChange ? [onChange] : []);
138
- }
139
- function deref(value) {
140
- return isKTRef(value) ? value.value : value;
141
- }
142
- function kcollect() {
143
- const newObj = {};
144
- const entries = $entries(this);
145
- for (let i = 0; i < entries.length; i++) {
146
- const key = entries[i][0];
147
- if (key === 'kcollect') {
148
- continue;
149
- }
150
- newObj[key] = entries[i][1].value;
151
- }
152
- return newObj;
153
- }
154
- /**
155
- * Make all first-level properties of the object a `KTRef`.
156
- * - `obj.a.b` is not reactive
157
- */
158
- const surfaceRef = (obj) => {
159
- const entries = $entries(obj);
160
- const newObj = { kcollect };
161
- for (let i = 0; i < entries.length; i++) {
162
- newObj[entries[i][0]] = ref(entries[i][1]);
163
- }
164
- return newObj;
165
- };
166
- // # asserts
167
- /**
168
- * Assert k-model to be a ref object
169
- */
170
- const $modelOrRef = (props, defaultValue) => {
171
- // & props is an object. Won't use it in any other place
172
- if ('k-model' in props) {
173
- const kmodel = props['k-model'];
174
- if (!kmodel?.isKT) {
175
- throw new Error(`[kt.js error] k-model data must be a KTRef object, please use 'ref(...)' to wrap it.`);
176
- }
177
- return kmodel;
178
- }
179
- return ref(defaultValue);
180
- };
90
+ // export const KT_TYPE_REF = 1 as const;
91
+ // export const KT_TYPE_COMPUTED = 2 as const;
92
+ // export type KTReactiveTypeEnum = typeof KT_TYPE_REF | typeof KT_TYPE_COMPUTED;
93
+ const isKT = (obj) => obj?.isKT;
94
+ const isRef = (obj) => obj?.ktType === 1 /* KTReactiveType.REF */;
95
+ const isComputed = (obj) => obj?.ktType === 2 /* KTReactiveType.COMPUTED */;
181
96
 
182
97
  const booleanHandler = (element, key, value) => {
183
98
  if (key in element) {
@@ -239,7 +154,7 @@ var __ktjs_core__ = (function (exports) {
239
154
  }
240
155
  if ('k-html' in attr) {
241
156
  const html = attr['k-html'];
242
- if (isKTRef(html)) {
157
+ if (isKT(html)) {
243
158
  element.innerHTML = html.value;
244
159
  html.addOnChange((v) => (element.innerHTML = v));
245
160
  }
@@ -248,14 +163,14 @@ var __ktjs_core__ = (function (exports) {
248
163
  }
249
164
  }
250
165
  for (const key in attr) {
251
- if (key === 'class' ||
166
+ if (key === 'k-if' ||
167
+ key === 'k-model' ||
168
+ key === 'ref' ||
169
+ key === 'class' ||
252
170
  key === 'className' ||
253
171
  key === 'style' ||
254
172
  key === 'children' ||
255
- key === 'k-if' ||
256
- key === 'k-model' ||
257
- key === 'k-html' ||
258
- key === 'ref') {
173
+ key === 'k-html') {
259
174
  continue;
260
175
  }
261
176
  const o = attr[key];
@@ -288,7 +203,7 @@ var __ktjs_core__ = (function (exports) {
288
203
  if (c === false || c === undefined || c === null) {
289
204
  return;
290
205
  }
291
- if (isKTRef(c)) {
206
+ if (isKT(c)) {
292
207
  let node = assureNode(c.value);
293
208
  $append.call(element, node);
294
209
  c.addOnChange((newValue, oldValue) => {
@@ -345,8 +260,218 @@ var __ktjs_core__ = (function (exports) {
345
260
  }
346
261
  }
347
262
 
263
+ class KTRef {
264
+ /**
265
+ * Indicates that this is a KTRef instance
266
+ */
267
+ isKT = true;
268
+ ktType = 1 /* KTReactiveType.REF */;
269
+ /**
270
+ * @internal
271
+ */
272
+ _value;
273
+ /**
274
+ * @internal
275
+ */
276
+ _onChanges;
277
+ constructor(_value, _onChanges) {
278
+ this._value = _value;
279
+ this._onChanges = _onChanges;
280
+ }
281
+ /**
282
+ * If new value and old value are both nodes, the old one will be replaced in the DOM
283
+ */
284
+ get value() {
285
+ return this._value;
286
+ }
287
+ set value(newValue) {
288
+ if ($is(newValue, this._value)) {
289
+ return;
290
+ }
291
+ const oldValue = this._value;
292
+ $replaceNode(oldValue, newValue);
293
+ this._value = newValue;
294
+ for (let i = 0; i < this._onChanges.length; i++) {
295
+ this._onChanges[i](newValue, oldValue);
296
+ }
297
+ }
298
+ /**
299
+ * Register a callback when the value changes
300
+ * @param callback (newValue, oldValue) => xxx
301
+ */
302
+ addOnChange(callback) {
303
+ if (typeof callback !== 'function') {
304
+ throw new Error('[kt.js error] KTRef.addOnChange: callback must be a function');
305
+ }
306
+ this._onChanges.push(callback);
307
+ }
308
+ removeOnChange(callback) {
309
+ for (let i = this._onChanges.length - 1; i >= 0; i--) {
310
+ if (this._onChanges[i] === callback) {
311
+ this._onChanges.splice(i, 1);
312
+ return true;
313
+ }
314
+ }
315
+ return false;
316
+ }
317
+ }
318
+ /**
319
+ * Reference to the created HTML element.
320
+ * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
321
+ * - can alse be used to store normal values, but it is not reactive.
322
+ * - if the value is already a `KTRef`, it will be returned **directly**.
323
+ * @param value mostly an HTMLElement
324
+ */
325
+ function ref(value, onChange) {
326
+ return new KTRef(value, onChange ? [onChange] : []);
327
+ }
328
+ /**
329
+ * Convert a value to `KTRef`.
330
+ * - Returns the original value if it is already a `KTRef`.
331
+ * - Throws error if the value is a `KTComputed`.
332
+ * - Otherwise wraps the value with `ref()`.
333
+ * @param o value to convert
334
+ */
335
+ const toRef = (o) => {
336
+ if (isRef(o)) {
337
+ return o;
338
+ }
339
+ else if (isComputed(o)) {
340
+ throw new Error('[kt.js error] Computed values cannot be used as KTRef.');
341
+ }
342
+ else {
343
+ return ref(o);
344
+ }
345
+ };
346
+ function deref(value) {
347
+ return isKT(value) ? value.value : value;
348
+ }
349
+ function kcollect() {
350
+ const newObj = {};
351
+ const entries = $entries(this);
352
+ for (let i = 0; i < entries.length; i++) {
353
+ const key = entries[i][0];
354
+ if (key === 'kcollect') {
355
+ continue;
356
+ }
357
+ newObj[key] = entries[i][1].value;
358
+ }
359
+ return newObj;
360
+ }
361
+ /**
362
+ * Make all first-level properties of the object a `KTRef`.
363
+ * - `obj.a.b` is not reactive
364
+ */
365
+ const surfaceRef = (obj) => {
366
+ const entries = $entries(obj);
367
+ const newObj = { kcollect };
368
+ for (let i = 0; i < entries.length; i++) {
369
+ newObj[entries[i][0]] = ref(entries[i][1]);
370
+ }
371
+ return newObj;
372
+ };
373
+ // # asserts
374
+ /**
375
+ * Assert k-model to be a ref object
376
+ */
377
+ const $modelOrRef = (props, defaultValue) => {
378
+ // & props is an object. Won't use it in any other place
379
+ if ('k-model' in props) {
380
+ const kmodel = props['k-model'];
381
+ if (!kmodel?.isKT) {
382
+ throw new Error(`[kt.js error] k-model data must be a KTRef object, please use 'ref(...)' to wrap it.`);
383
+ }
384
+ return kmodel;
385
+ }
386
+ return ref(defaultValue);
387
+ };
388
+
389
+ class KTComputed {
390
+ /**
391
+ * Indicates that this is a KTRef instance
392
+ */
393
+ isKT = true;
394
+ ktType = 2 /* KTReactiveType.COMPUTED */;
395
+ /**
396
+ * @internal
397
+ */
398
+ _calculator;
399
+ /**
400
+ * @internal
401
+ */
402
+ _value;
403
+ /**
404
+ * @internal
405
+ */
406
+ _onChanges = [];
407
+ _subscribe(reactives) {
408
+ for (let i = 0; i < reactives.length; i++) {
409
+ const reactive = reactives[i];
410
+ reactive.addOnChange(() => {
411
+ const oldValue = this._value;
412
+ this._value = this._calculator();
413
+ if (oldValue === this._value) {
414
+ return;
415
+ }
416
+ $replaceNode(oldValue, this._value);
417
+ for (let i = 0; i < this._onChanges.length; i++) {
418
+ this._onChanges[i](this._value, oldValue);
419
+ }
420
+ });
421
+ }
422
+ }
423
+ constructor(_calculator, reactives) {
424
+ this._calculator = _calculator;
425
+ this._value = _calculator();
426
+ this._subscribe(reactives);
427
+ }
428
+ /**
429
+ * If new value and old value are both nodes, the old one will be replaced in the DOM
430
+ */
431
+ get value() {
432
+ return this._value;
433
+ }
434
+ set value(_newValue) {
435
+ throw new Error('[kt.js error] KTComputed: cannot set value of a computed value');
436
+ }
437
+ /**
438
+ * Register a callback when the value changes
439
+ * @param callback (newValue, oldValue) => xxx
440
+ */
441
+ addOnChange(callback) {
442
+ if (typeof callback !== 'function') {
443
+ throw new Error('[kt.js error] KTRef.addOnChange: callback must be a function');
444
+ }
445
+ this._onChanges.push(callback);
446
+ }
447
+ /**
448
+ * Unregister a callback
449
+ * @param callback (newValue, oldValue) => xxx
450
+ */
451
+ removeOnChange(callback) {
452
+ for (let i = this._onChanges.length - 1; i >= 0; i--) {
453
+ if (this._onChanges[i] === callback) {
454
+ this._onChanges.splice(i, 1);
455
+ return true;
456
+ }
457
+ }
458
+ return false;
459
+ }
460
+ }
461
+ /**
462
+ * Create a reactive computed value
463
+ * @param computeFn
464
+ * @param reactives refs and computeds that this computed depends on
465
+ */
466
+ function computed(computeFn, reactives) {
467
+ if (reactives.some((v) => !isKT(v))) {
468
+ throw new Error('[kt.js error] computed: all reactives must be KTRef or KTComputed instances');
469
+ }
470
+ return new KTComputed(computeFn, reactives);
471
+ }
472
+
348
473
  function applyKModel(element, valueRef) {
349
- if (!isKTRef(valueRef)) {
474
+ if (!isKT(valueRef)) {
350
475
  console.warn('[kt.js warn] k-model value must be a KTRef.');
351
476
  return;
352
477
  }
@@ -373,9 +498,6 @@ var __ktjs_core__ = (function (exports) {
373
498
  const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
374
499
  const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
375
500
  let creator = htmlCreator;
376
- // # consts
377
- const SVG_ATTR_FLAG = '__kt_svg__';
378
- const MATHML_ATTR_FLAG = '__kt_mathml__';
379
501
  /**
380
502
  * Create an enhanced HTMLElement.
381
503
  * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
@@ -386,7 +508,7 @@ var __ktjs_core__ = (function (exports) {
386
508
  * ## About
387
509
  * @package @ktjs/core
388
510
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
389
- * @version 0.23.0 (Last Update: 2026.02.03 17:15:01.812)
511
+ * @version 0.24.0 (Last Update: 2026.02.05 12:08:54.164)
390
512
  * @license MIT
391
513
  * @link https://github.com/baendlorel/kt.js
392
514
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -416,13 +538,7 @@ var __ktjs_core__ = (function (exports) {
416
538
  applyAttr(element, attr);
417
539
  applyContent(element, content);
418
540
  if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
419
- const kmodel = attr['k-model'];
420
- if (isKTRef(kmodel)) {
421
- applyKModel(element, kmodel);
422
- }
423
- else {
424
- throw new Error('[kt.js error] k-model value must be a KTRef.');
425
- }
541
+ applyKModel(element, attr['k-model']);
426
542
  }
427
543
  return element;
428
544
  };
@@ -442,20 +558,23 @@ var __ktjs_core__ = (function (exports) {
442
558
  * @param props properties/attributes
443
559
  */
444
560
  function jsx(tag, props) {
445
- const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
561
+ if (isComputed(props.ref)) {
562
+ throw new Error('[kt.js error] Cannot assign a computed value to an element.');
563
+ }
564
+ const maybeDummyRef = isRef(props.ref) ? props.ref : dummyRef;
446
565
  let el;
447
566
  if ('k-if' in props) {
448
567
  const kif = props['k-if'];
449
568
  let condition = kif; // assume boolean by default
450
569
  // Handle reactive k-if
451
- if (isKTRef(kif)) {
570
+ if (isKT(kif)) {
452
571
  kif.addOnChange((newValue, oldValue) => {
453
572
  if (newValue === oldValue) {
454
573
  return;
455
574
  }
456
575
  const oldEl = el;
457
576
  el = newValue ? create(tag, props) : placeholder();
458
- oldEl.replaceWith(el);
577
+ $replaceNode(oldEl, el);
459
578
  maybeDummyRef.value = el;
460
579
  });
461
580
  condition = kif.value;
@@ -712,7 +831,7 @@ var __ktjs_core__ = (function (exports) {
712
831
  return anchor;
713
832
  };
714
833
  // Set ref if provided
715
- if (props.ref?.isKT) {
834
+ if (isRef(props.ref)) {
716
835
  props.ref.value = anchor;
717
836
  }
718
837
  return anchor;
@@ -763,18 +882,23 @@ var __ktjs_core__ = (function (exports) {
763
882
  exports.$modelOrRef = $modelOrRef;
764
883
  exports.Fragment = Fragment;
765
884
  exports.KTAsync = KTAsync;
885
+ exports.KTComputed = KTComputed;
766
886
  exports.KTFor = KTFor;
767
887
  exports.KTRef = KTRef;
888
+ exports.computed = computed;
768
889
  exports.createElement = h;
769
890
  exports.createRedrawable = createRedrawable;
770
891
  exports.deref = deref;
771
892
  exports.h = h;
772
- exports.isKTRef = isKTRef;
893
+ exports.isComputed = isComputed;
894
+ exports.isKT = isKT;
895
+ exports.isRef = isRef;
773
896
  exports.jsx = jsx;
774
897
  exports.jsxDEV = jsxDEV;
775
898
  exports.jsxs = jsxs;
776
899
  exports.ref = ref;
777
900
  exports.surfaceRef = surfaceRef;
901
+ exports.toRef = toRef;
778
902
 
779
903
  return exports;
780
904