@ktjs/core 0.32.5 → 0.33.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.
package/dist/index.mjs CHANGED
@@ -1,40 +1,10 @@
1
- import { $isArray, $isThenable, $isNode, $is, $emptyFn, $applyModel, $forEach, $identity } from '@ktjs/shared';
1
+ import { $isArray, $isThenable, $isNode, $emptyFn, $is, $applyModel, $forEach, $identity } from "@ktjs/shared";
2
2
 
3
- const isKT = (obj) => obj?.isKT;
4
- const isRef = (obj) => {
5
- // & This is tested to be the fastest way.
6
- // faster than includes, arrayindex, if or.
7
- if (obj.ktType === undefined) {
8
- return false;
9
- }
10
- return obj.ktType >= 2 /* KTReactiveType.Ref */;
11
- };
12
- const isArrayRef = (obj) => obj?.ktType === 4 /* KTReactiveType.ArrayRef */;
13
- const isMapRef = (obj) => obj?.ktType === 5 /* KTReactiveType.MapRef */;
14
- const isSetRef = (obj) => obj?.ktType === 6 /* KTReactiveType.SetRef */;
15
- const isWeakMapRef = (obj) => obj?.ktType === 7 /* KTReactiveType.WeakMapRef */;
16
- const isWeakSetRef = (obj) => obj?.ktType === 8 /* KTReactiveType.WeakSetRef */;
17
- const isDateRef = (obj) => obj?.ktType === 9 /* KTReactiveType.DateRef */;
18
- const isComputed = (obj) => obj?.ktType === 1 /* KTReactiveType.Computed */;
19
-
20
- const booleanHandler = (element, key, value) => {
21
- if (key in element) {
22
- element[key] = !!value;
23
- }
24
- else {
25
- element.setAttribute(key, value);
26
- }
27
- };
28
- const valueHandler = (element, key, value) => {
29
- if (key in element) {
30
- element[key] = value;
31
- }
32
- else {
33
- element.setAttribute(key, value);
34
- }
35
- };
36
- // Attribute handlers map for optimized lookup
37
- const handlers = {
3
+ const isKT = obj => obj?.isKT, isRef = obj => void 0 !== obj.ktType && 3 === obj.ktType, isComputed = obj => 2 === obj?.ktType, booleanHandler = (element, key, value) => {
4
+ key in element ? element[key] = !!value : element.setAttribute(key, value);
5
+ }, valueHandler = (element, key, value) => {
6
+ key in element ? element[key] = value : element.setAttribute(key, value);
7
+ }, handlers = {
38
8
  checked: booleanHandler,
39
9
  selected: booleanHandler,
40
10
  value: valueHandler,
@@ -55,777 +25,224 @@ const handlers = {
55
25
  muted: booleanHandler,
56
26
  defer: booleanHandler,
57
27
  async: booleanHandler,
58
- hidden: (element, _key, value) => (element.hidden = !!value),
28
+ hidden: (element, _key, value) => element.hidden = !!value
29
+ }, defaultHandler = (element, key, value) => element.setAttribute(key, value), setElementStyle = (element, style) => {
30
+ if ("string" != typeof style) for (const key in style) element.style[key] = style[key]; else element.style.cssText = style;
59
31
  };
60
32
 
61
- const defaultHandler = (element, key, value) => element.setAttribute(key, value);
62
- const setElementStyle = (element, style) => {
63
- if (typeof style === 'string') {
64
- element.style.cssText = style;
65
- return;
66
- }
67
- for (const key in style) {
68
- element.style[key] = style[key];
69
- }
70
- };
71
- function attrIsObject(element, attr) {
72
- const classValue = attr.class || attr.className;
73
- if (classValue !== undefined) {
74
- if (isKT(classValue)) {
75
- element.setAttribute('class', classValue.value);
76
- classValue.addOnChange((v) => element.setAttribute('class', v));
77
- }
78
- else {
79
- element.setAttribute('class', classValue);
80
- }
81
- }
82
- const style = attr.style;
83
- if (style) {
84
- if (typeof style === 'string') {
85
- element.setAttribute('style', style);
86
- }
87
- else if (typeof style === 'object') {
88
- if (isKT(style)) {
89
- setElementStyle(element, style.value);
90
- style.addOnChange((v) => setElementStyle(element, v));
91
- }
92
- else {
93
- setElementStyle(element, style);
33
+ function applyAttr(element, attr) {
34
+ if (attr) {
35
+ if ("object" != typeof attr || null === attr) throw new Error("[@ktjs/core error] attr must be an object.");
36
+ !function(element, attr) {
37
+ const classValue = attr.class || attr.className;
38
+ void 0 !== classValue && (isKT(classValue) ? (element.setAttribute("class", classValue.value),
39
+ classValue.addOnChange(v => element.setAttribute("class", v))) : element.setAttribute("class", classValue));
40
+ const style = attr.style;
41
+ if (style && ("string" == typeof style ? element.setAttribute("style", style) : "object" == typeof style && (isKT(style) ? (setElementStyle(element, style.value),
42
+ style.addOnChange(v => setElementStyle(element, v))) : setElementStyle(element, style))),
43
+ "k-html" in attr) {
44
+ const html = attr["k-html"];
45
+ isKT(html) ? (element.innerHTML = html.value, html.addOnChange(v => element.innerHTML = v)) : element.innerHTML = html;
94
46
  }
95
- }
96
- }
97
- if ('k-html' in attr) {
98
- const html = attr['k-html'];
99
- if (isKT(html)) {
100
- element.innerHTML = html.value;
101
- html.addOnChange((v) => (element.innerHTML = v));
102
- }
103
- else {
104
- element.innerHTML = html;
105
- }
106
- }
107
- for (const key in attr) {
108
- // & Arranged in order of usage frequency
109
- if (
110
- // key === 'k-if' ||
111
- // key === 'k-else' ||
112
- key === 'k-model' ||
113
- key === 'k-for' ||
114
- key === 'k-key' ||
115
- key === 'ref' ||
116
- key === 'class' ||
117
- key === 'className' ||
118
- key === 'style' ||
119
- key === 'children' ||
120
- key === 'k-html') {
121
- continue;
122
- }
123
- const o = attr[key];
124
- // normal event handler
125
- if (key.startsWith('on:')) {
126
- if (o) {
127
- element.addEventListener(key.slice(3), o); // chop off the `on:`
47
+ for (const key in attr) {
48
+ if ("k-model" === key || "k-for" === key || "k-key" === key || "ref" === key || "class" === key || "className" === key || "style" === key || "children" === key || "k-html" === key) continue;
49
+ const o = attr[key];
50
+ if (key.startsWith("on:")) {
51
+ o && element.addEventListener(key.slice(3), o);
52
+ continue;
53
+ }
54
+ const handler = handlers[key] || defaultHandler;
55
+ isKT(o) ? (handler(element, key, o.value), o.addOnChange(v => handler(element, key, v))) : handler(element, key, o);
128
56
  }
129
- continue;
130
- }
131
- // normal attributes
132
- const handler = handlers[key] || defaultHandler;
133
- if (isKT(o)) {
134
- handler(element, key, o.value);
135
- o.addOnChange((v) => handler(element, key, v));
136
- }
137
- else {
138
- handler(element, key, o);
139
- }
140
- }
141
- }
142
- function applyAttr(element, attr) {
143
- if (!attr) {
144
- return;
145
- }
146
- if (typeof attr === 'object' && attr !== null) {
147
- attrIsObject(element, attr);
148
- }
149
- else {
150
- throw new Error('[@ktjs/core error] attr must be an object.');
57
+ }(element, attr);
151
58
  }
152
59
  }
153
60
 
154
- const assureNode = (o) => ($isNode(o) ? o : document.createTextNode(o));
61
+ const assureNode = o => $isNode(o) ? o : document.createTextNode(o);
62
+
155
63
  function apdSingle(element, c) {
156
- // & Ignores falsy values, consistent with React's behavior
157
- if (c === undefined || c === null || c === false) {
158
- return;
159
- }
160
- if (isKT(c)) {
64
+ if (null != c && !1 !== c) if (isKT(c)) {
161
65
  let node = assureNode(c.value);
162
- element.appendChild(node);
163
- c.addOnChange((newValue, _oldValue) => {
66
+ element.appendChild(node), c.addOnChange((newValue, _oldValue) => {
164
67
  const oldNode = node;
165
- node = assureNode(newValue);
166
- oldNode.replaceWith(node);
68
+ node = assureNode(newValue), oldNode.replaceWith(node);
167
69
  });
168
- }
169
- else {
70
+ } else {
170
71
  const node = assureNode(c);
171
72
  element.appendChild(node);
172
- // Handle KTFor anchor
173
73
  const list = node.__kt_for_list__;
174
- if ($isArray(list)) {
175
- apd(element, list);
176
- }
74
+ $isArray(list) && apd(element, list);
177
75
  }
178
76
  }
77
+
179
78
  function apd(element, c) {
180
- if ($isThenable(c)) {
181
- c.then((r) => apd(element, r));
182
- }
183
- else if ($isArray(c)) {
184
- for (let i = 0; i < c.length; i++) {
185
- // & might be thenable here too
186
- const ci = c[i];
187
- if ($isThenable(ci)) {
188
- const comment = document.createComment('ktjs-promise-placeholder');
189
- element.appendChild(comment);
190
- ci.then((awaited) => comment.replaceWith(awaited));
191
- }
192
- else {
193
- apdSingle(element, ci);
194
- }
195
- }
196
- }
197
- else {
198
- // & here is thened, so must be a simple elementj
199
- apdSingle(element, c);
200
- }
79
+ if ($isThenable(c)) c.then(r => apd(element, r)); else if ($isArray(c)) for (let i = 0; i < c.length; i++) {
80
+ const ci = c[i];
81
+ if ($isThenable(ci)) {
82
+ const comment = document.createComment("ktjs-promise-placeholder");
83
+ element.appendChild(comment), ci.then(awaited => comment.replaceWith(awaited));
84
+ } else apdSingle(element, ci);
85
+ } else apdSingle(element, c);
201
86
  }
87
+
202
88
  function applyContent(element, content) {
203
- if ($isArray(content)) {
204
- for (let i = 0; i < content.length; i++) {
205
- apd(element, content[i]);
206
- }
207
- }
208
- else {
209
- apd(element, content);
210
- }
89
+ if ($isArray(content)) for (let i = 0; i < content.length; i++) apd(element, content[i]); else apd(element, content);
211
90
  }
212
91
 
213
- // # internal methods that cannot be placed in @ktjs/shared
214
92
  const IdGenerator = {
215
93
  _refOnChangeId: 1,
216
94
  get refOnChangeId() {
217
95
  return this._refOnChangeId++;
218
- },
219
- _computedOnChangeId: 1,
220
- get computedOnChangeId() {
221
- return this._computedOnChangeId++;
222
- }};
223
-
224
- class KTComputed {
225
- /**
226
- * Indicates that this is a KTRef instance
227
- */
228
- isKT = true;
229
- ktType = 1 /* KTReactiveType.Computed */;
230
- /**
231
- * @internal
232
- */
233
- _calculator;
234
- /**
235
- * @internal
236
- */
237
- _value;
238
- /**
239
- * @internal
240
- */
241
- _onChanges = new Map();
242
- /**
243
- * @internal
244
- */
245
- _emit(newValue, oldValue, handlerKeys) {
246
- if (handlerKeys) {
247
- for (let i = 0; i < handlerKeys.length; i++) {
248
- this._onChanges.get(handlerKeys[i])?.(newValue, oldValue);
249
- }
250
- return;
251
- }
252
- this._onChanges.forEach((c) => c(newValue, oldValue));
253
- }
254
- /**
255
- * @internal
256
- */
257
- _recalculate(forceEmit = false, handlerKeys) {
258
- const oldValue = this._value;
259
- const newValue = this._calculator();
260
- if (oldValue === newValue) {
261
- if (forceEmit) {
262
- this._emit(newValue, oldValue, handlerKeys);
263
- }
264
- return;
265
- }
266
- this._value = newValue;
267
- this._emit(newValue, oldValue, handlerKeys);
268
- }
269
- /**
270
- * @internal
271
- */
272
- _subscribe(reactives) {
273
- for (let i = 0; i < reactives.length; i++) {
274
- const reactive = reactives[i];
275
- reactive.addOnChange(() => this._recalculate());
276
- }
277
96
  }
278
- constructor(_calculator, reactives) {
279
- this._calculator = _calculator;
280
- this._value = _calculator();
281
- this._subscribe(reactives);
282
- }
283
- /**
284
- * If new value and old value are both nodes, the old one will be replaced in the DOM
285
- */
286
- get value() {
287
- return this._value;
288
- }
289
- set value(_newValue) {
290
- throw new Error('[@ktjs/core error] KTComputed: cannot set value of a computed value');
291
- }
292
- /**
293
- * Force listeners to run once with the latest computed result.
294
- */
295
- notify(handlerKeys) {
296
- this._recalculate(true, handlerKeys);
297
- }
298
- /**
299
- * Computed values are derived from dependencies and should not be mutated manually.
300
- */
301
- mutate(_mutator, handlerKeys) {
302
- console.warn('[@ktjs/core warn]','KTComputed.mutate: computed is derived automatically; manual mutate is ignored. Use notify() instead');
303
- if (handlerKeys) {
304
- this._emit(this._value, this._value, handlerKeys);
305
- }
306
- return this._value;
307
- }
308
- toComputed(calculator, dependencies) {
309
- return computed(() => calculator(this.value), dependencies ? [this, ...dependencies] : [this]);
310
- }
311
- /**
312
- * Register a callback when the value changes
313
- * @param callback (newValue, oldValue) => xxx
314
- */
315
- addOnChange(callback, key) {
316
- if (typeof callback !== 'function') {
317
- throw new Error('[@ktjs/core error] KTComputed.addOnChange: callback must be a function');
318
- }
319
- const k = key ?? IdGenerator.computedOnChangeId;
320
- this._onChanges.set(k, callback);
321
- return k;
322
- }
323
- /**
324
- * Unregister a callback
325
- * @param key registered listener key
326
- */
327
- removeOnChange(key) {
328
- const callback = this._onChanges.get(key);
329
- this._onChanges.delete(key);
330
- return callback;
331
- }
332
- }
333
- /**
334
- * Create a reactive computed value
335
- * @param computeFn
336
- * @param dependencies refs and computeds that this computed depends on
337
- */
338
- function computed(computeFn, dependencies) {
339
- if (dependencies.some((v) => !isKT(v))) {
340
- throw new Error('[@ktjs/core error] computed: all reactives must be KTRef or KTComputed instances');
341
- }
342
- return new KTComputed(computeFn, dependencies);
343
- }
97
+ };
344
98
 
345
- class KTRef {
346
- /**
347
- * Indicates that this is a KTRef instance
348
- */
349
- isKT = true;
350
- ktType = 2 /* KTReactiveType.Ref */;
351
- /**
352
- * @internal
353
- */
99
+ class KTReactive {
100
+ isKT=!0;
101
+ ktType=1;
354
102
  _value;
355
- /**
356
- * @internal
357
- */
358
- _onChanges;
359
- /**
360
- * @internal
361
- */
103
+ _changeHandlers=new Map;
362
104
  _emit(newValue, oldValue, handlerKeys) {
363
105
  if (handlerKeys) {
364
- for (let i = 0; i < handlerKeys.length; i++) {
365
- this._onChanges.get(handlerKeys[i])?.(newValue, oldValue);
366
- }
367
- return;
106
+ for (let i = 0; i < handlerKeys.length; i++) this._changeHandlers.get(handlerKeys[i])?.(newValue, oldValue);
107
+ return this;
368
108
  }
369
- this._onChanges.forEach((c) => c(newValue, oldValue));
109
+ return this._changeHandlers.forEach(c => c(newValue, oldValue)), this;
370
110
  }
371
- constructor(_value, _onChange) {
372
- this._value = _value;
373
- this._onChanges = new Map();
374
- if (_onChange) {
375
- this._onChanges.set(IdGenerator.refOnChangeId, _onChange);
376
- }
111
+ constructor(_value) {
112
+ this._value = _value, this._changeHandlers = new Map;
377
113
  }
378
- /**
379
- * If new value and old value are both nodes, the old one will be replaced in the DOM
380
- */
381
114
  get value() {
382
115
  return this._value;
383
116
  }
384
- set value(newValue) {
385
- if ($is(newValue, this._value)) {
386
- return;
387
- }
388
- const oldValue = this._value;
389
- this._value = newValue;
390
- this._emit(newValue, oldValue);
391
- }
392
- /**
393
- * Force all listeners to run even when reference identity has not changed.
394
- * Useful for in-place array/object mutations.
395
- */
117
+ set value(_newValue) {}
396
118
  notify(handlerKeys) {
397
- this._emit(this._value, this._value, handlerKeys);
398
- }
399
- /**
400
- * Mutate current value in-place and notify listeners once.
401
- *
402
- * @example
403
- * const items = ref<number[]>([1, 2]);
404
- * items.mutate((list) => list.push(3));
405
- */
406
- mutate(mutator, handlerKeys) {
407
- if (typeof mutator !== 'function') {
408
- throw new Error('[@ktjs/core error] KTRef.mutate: mutator must be a function');
409
- }
410
- const oldValue = this._value;
411
- const result = mutator(this._value);
412
- this._emit(this._value, oldValue, handlerKeys);
413
- return result;
119
+ return this._emit(this._value, this._value, handlerKeys);
414
120
  }
415
- toComputed(calculator, dependencies) {
416
- return computed(() => calculator(this.value), dependencies ? [this, ...dependencies] : [this]);
121
+ map(..._args) {
122
+ throw new Error("This is meant to be override in computed.ts");
417
123
  }
418
- /**
419
- * Register a callback when the value changes
420
- * @param callback (newValue, oldValue) => xxx
421
- * @param key Optional key to identify the callback, allowing multiple listeners on the same ref and individual removal. If not provided, a unique ID will be generated.
422
- */
423
124
  addOnChange(callback, key) {
424
- if (typeof callback !== 'function') {
425
- throw new Error('[@ktjs/core error] KTRef.addOnChange: callback must be a function');
426
- }
125
+ if ("function" != typeof callback) throw new Error("[@ktjs/core error] KTRef.addOnChange: callback must be a function");
427
126
  const k = key ?? IdGenerator.refOnChangeId;
428
- this._onChanges.set(k, callback);
429
- return k;
127
+ return this._changeHandlers.set(k, callback), this;
430
128
  }
431
129
  removeOnChange(key) {
432
- const callback = this._onChanges.get(key);
433
- this._onChanges.delete(key);
434
- return callback;
130
+ const callback = this._changeHandlers.get(key);
131
+ return this._changeHandlers.delete(key), callback;
435
132
  }
436
133
  }
437
134
 
438
- /**
439
- * Calls the setter-like function and emit all changes of it
440
- */
441
- const apply = (r, setter, args) => {
442
- const v = r.value;
443
- const result = setter.apply(v, args);
444
- r._onChanges.forEach((handler) => handler(v, v));
445
- return result;
446
- };
447
- const applyArgless = (r, setter) => {
448
- const v = r.value;
449
- const result = setter.apply(v);
450
- r._onChanges.forEach((handler) => handler(v, v));
451
- return result;
452
- };
135
+ const reactiveToOldValue = new Map;
453
136
 
454
- class KTArrayRef extends KTRef {
455
- constructor(value, onChange) {
456
- super(value, onChange);
457
- this.ktType = 4 /* KTReactiveType.ArrayRef */;
458
- }
459
- get length() {
460
- return this.value.length;
461
- }
462
- set length(newLength) {
463
- this._value.length = newLength;
464
- this._onChanges.forEach((handler) => handler(this._value, this._value));
465
- }
466
- push(...items) {
467
- return apply(this, this._value.push, items);
468
- }
469
- /**
470
- * Same as `Array.prototype.pop`, but emits change after calling it
471
- */
472
- pop() {
473
- return applyArgless(this, this._value.pop);
474
- }
475
- /**
476
- * Same as `Array.prototype.shift`, but emits change after calling it
477
- */
478
- shift() {
479
- return applyArgless(this, this._value.shift);
480
- }
481
- /**
482
- * Same as `Array.prototype.unshift`, but emits change after calling it
483
- */
484
- unshift(...items) {
485
- return apply(this, this._value.unshift, items);
486
- }
487
- splice(...args) {
488
- return apply(this, this._value.splice, args);
489
- }
490
- sort(...args) {
491
- apply(this, this._value.sort, args);
492
- return this;
493
- }
494
- /**
495
- * Same as `Array.prototype.reverse`, but emits change after calling it
496
- */
497
- reverse() {
498
- applyArgless(this, this._value.reverse);
499
- return this;
500
- }
501
- fill(...args) {
502
- apply(this, this._value.fill, args);
503
- return this;
504
- }
505
- copyWithin(...args) {
506
- apply(this, this._value.copyWithin, args);
507
- return this;
508
- }
509
- }
510
- const arrayRef = (value, onChange) => new KTArrayRef(value, onChange);
137
+ let scheduled = !1;
511
138
 
512
- class KTDateRef extends KTRef {
513
- constructor(value, onChange) {
514
- super(value, onChange);
515
- this.ktType = 9 /* KTReactiveType.DateRef */;
516
- }
517
- setTime(timeValue) {
518
- return apply(this, this._value.setTime, [timeValue]);
519
- }
520
- setMilliseconds(millisecondsValue) {
521
- return apply(this, this._value.setMilliseconds, [millisecondsValue]);
522
- }
523
- setUTCMilliseconds(millisecondsValue) {
524
- return apply(this, this._value.setUTCMilliseconds, [millisecondsValue]);
525
- }
526
- setSeconds(...args) {
527
- return apply(this, this._value.setSeconds, args);
528
- }
529
- setUTCSeconds(...args) {
530
- return apply(this, this._value.setUTCSeconds, args);
531
- }
532
- setMinutes(...args) {
533
- return apply(this, this._value.setMinutes, args);
534
- }
535
- setUTCMinutes(...args) {
536
- return apply(this, this._value.setUTCMinutes, args);
537
- }
538
- setHours(...args) {
539
- return apply(this, this._value.setHours, args);
540
- }
541
- setUTCHours(...args) {
542
- return apply(this, this._value.setUTCHours, args);
543
- }
544
- setDate(dateValue) {
545
- return apply(this, this._value.setDate, [dateValue]);
546
- }
547
- setUTCDate(dateValue) {
548
- return apply(this, this._value.setUTCDate, [dateValue]);
549
- }
550
- setMonth(...args) {
551
- return apply(this, this._value.setMonth, args);
552
- }
553
- setUTCMonth(...args) {
554
- return apply(this, this._value.setUTCMonth, args);
555
- }
556
- setFullYear(...args) {
557
- return apply(this, this._value.setFullYear, args);
558
- }
559
- setUTCFullYear(...args) {
560
- return apply(this, this._value.setUTCFullYear, args);
561
- }
562
- }
563
- const dateRef = (value, onChange) => new KTDateRef(value, onChange);
564
-
565
- class KTMapRef extends KTRef {
566
- constructor(value, onChange) {
567
- super(value, onChange);
568
- this.ktType = 5 /* KTReactiveType.MapRef */;
569
- }
570
- get size() {
571
- return this._value.size;
572
- }
573
- has(key) {
574
- return this._value.has(key);
575
- }
576
- get(key) {
577
- return this._value.get(key);
578
- }
579
- set(key, value) {
580
- apply(this, this._value.set, [key, value]);
581
- return this;
582
- }
583
- delete(key) {
584
- return apply(this, this._value.delete, [key]);
139
+ class KTRef extends KTReactive {
140
+ ktType=3;
141
+ get value() {
142
+ return this._value;
585
143
  }
586
- clear() {
587
- return applyArgless(this, this._value.clear);
144
+ set value(newValue) {
145
+ if ($is(newValue, this._value)) return;
146
+ const oldValue = this._value;
147
+ this._value = newValue, this._emit(newValue, oldValue);
148
+ }
149
+ get draft() {
150
+ return (reactive => {
151
+ if (!reactiveToOldValue.has(reactive)) {
152
+ if (reactiveToOldValue.set(reactive, reactive._value), scheduled) return;
153
+ scheduled = !0, Promise.resolve().then(() => {
154
+ scheduled = !1, reactiveToOldValue.forEach((oldValue, reactive) => {
155
+ reactive._changeHandlers.forEach(handler => handler(reactive.value, oldValue));
156
+ }), reactiveToOldValue.clear();
157
+ });
158
+ }
159
+ })(this), this._value;
588
160
  }
589
161
  }
590
- const mapRef = (value, onChange) => new KTMapRef(value, onChange);
591
162
 
592
- class KTSetRef extends KTRef {
593
- constructor(value, onChange) {
594
- super(value, onChange);
595
- this.ktType = 6 /* KTReactiveType.SetRef */;
596
- }
597
- get size() {
598
- return this._value.size;
163
+ const ref = value => new KTRef(value), $modelOrRef = (props, defaultValue) => {
164
+ if ("k-model" in props) {
165
+ const kmodel = props["k-model"];
166
+ if (isRef(kmodel)) return kmodel;
167
+ throw new Error("[@ktjs/core error] k-model data must be a KTRef object, please use 'ref(...)' to wrap it.");
599
168
  }
600
- has(value) {
601
- return this._value.has(value);
602
- }
603
- add(value) {
604
- apply(this, this._value.add, [value]);
605
- return this;
606
- }
607
- delete(value) {
608
- return apply(this, this._value.delete, [value]);
609
- }
610
- clear() {
611
- return applyArgless(this, this._value.clear);
612
- }
613
- }
614
- const setRef = (value, onChange) => new KTSetRef(value, onChange);
169
+ return ref(defaultValue);
170
+ }, $refSetter = (props, node) => props.ref.value = node, $initRef = (props, node) => {
171
+ if (!("ref" in props)) return $emptyFn;
172
+ const r = props.ref;
173
+ if (isRef(r)) return r.value = node, $refSetter;
174
+ throw new Error("[@ktjs/core error] Fragment: ref must be a KTRef");
175
+ };
615
176
 
616
- class KTWeakMapRef extends KTRef {
617
- constructor(value, onChange) {
618
- super(value, onChange);
619
- this.ktType = 7 /* KTReactiveType.WeakMapRef */;
620
- }
621
- has(key) {
622
- return this._value.has(key);
623
- }
624
- get(key) {
625
- return this._value.get(key);
626
- }
627
- set(key, value) {
628
- apply(this, this._value.set, [key, value]);
629
- return this;
630
- }
631
- delete(key) {
632
- return apply(this, this._value.delete, [key]);
177
+ class KTComputed extends KTReactive {
178
+ ktType=2;
179
+ _calculator;
180
+ _recalculate(forceEmit = !1, handlerKeys) {
181
+ const oldValue = this._value, newValue = this._calculator();
182
+ return oldValue === newValue ? (forceEmit && this._emit(newValue, oldValue, handlerKeys),
183
+ this) : (this._value = newValue, this._emit(newValue, oldValue, handlerKeys), this);
633
184
  }
634
- }
635
- const weakMapRef = (value, onChange) => new KTWeakMapRef(value, onChange);
636
-
637
- class KTWeakSetRef extends KTRef {
638
- constructor(value, onChange) {
639
- super(value, onChange);
640
- this.ktType = 8 /* KTReactiveType.WeakSetRef */;
185
+ constructor(_calculator, dependencies) {
186
+ super(_calculator()), this._calculator = _calculator;
187
+ for (let i = 0; i < dependencies.length; i++) dependencies[i].addOnChange(() => this._recalculate());
641
188
  }
642
- has(value) {
643
- return this._value.has(value);
189
+ get value() {
190
+ return this._value;
644
191
  }
645
- add(value) {
646
- apply(this, this._value.add, [value]);
647
- return this;
192
+ set value(_newValue) {
193
+ console.warn("[@ktjs/core warn]", "'value' of Computed are read-only.");
648
194
  }
649
- delete(value) {
650
- return apply(this, this._value.delete, [value]);
195
+ notify(handlerKeys) {
196
+ return this._recalculate(!0, handlerKeys);
651
197
  }
652
198
  }
653
- const weakSetRef = (value, onChange) => new KTWeakSetRef(value, onChange);
654
199
 
655
- /**
656
- * Reference to the created HTML element or other reactive data.
657
- * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
658
- * - Automatically wrap the value with corresponding ref type based on its type.
659
- * - When wrapped, setter-like methods will be reactive. like `push` for `Array`, `set` for `Map`, `add` for `Set`, etc.
660
- * - Supports: `Array`, `Map`, `Set`, `WeakMap`, `WeakSet`, `Date`.
661
- * - Since there will be some cost for runtime detection, and compilation plugin might not be able to analyze all cases. It is recommended to use specific ref type directly if you already know the type of value, like `ref.array`, `ref.map`, etc.
662
- * @param value any data
663
- * @param onChange event handler triggered when the value changes, with signature `(newValue, oldValue) => void`
664
- */
665
- function autoRef(value, onChange) {
666
- if (Array.isArray(value)) {
667
- return arrayRef(value, onChange);
668
- }
669
- if (value instanceof Map) {
670
- return mapRef(value, onChange);
671
- }
672
- if (value instanceof Set) {
673
- return setRef(value, onChange);
674
- }
675
- if (value instanceof WeakMap) {
676
- return weakMapRef(value, onChange);
677
- }
678
- if (value instanceof WeakSet) {
679
- return weakSetRef(value, onChange);
680
- }
681
- if (value instanceof Date) {
682
- return dateRef(value, onChange);
683
- }
684
- return new KTRef(value, onChange);
200
+ function computed(computeFn, dependencies) {
201
+ if (dependencies.some(v => !isKT(v))) throw new Error("[@ktjs/core error] computed: all reactives must be KTRef or KTComputed instances");
202
+ return new KTComputed(computeFn, dependencies);
685
203
  }
686
- // todo 编译时期,插件要尽量分析出谁是谁,并基于最大限度的覆写支持,避免运行时for循环创建ref
687
- /**
688
- * Create a plain `KTRef` object.
689
- *
690
- * If you want the value to be automatically wrapped with corresponding ref type based on its type, please use `autoRef` instead.
691
- *
692
- * @param value any data
693
- * @param onChange event handler triggered when the value changes, with signature `(newValue, oldValue) => void`
694
- * @returns
695
- */
696
- const ref = ((value, onChange) => new KTRef(value, onChange));
697
- ref.array = arrayRef;
698
- ref.date = dateRef;
699
- ref.map = mapRef;
700
- ref.set = setRef;
701
- ref.weakMap = weakMapRef;
702
- ref.weakSet = weakSetRef;
703
- /**
704
- * Assert k-model to be a ref object
705
- */
706
- const $modelOrRef = (props, defaultValue) => {
707
- // & props is an object. Won't use it in any other place
708
- if ('k-model' in props) {
709
- const kmodel = props['k-model'];
710
- if (isRef(kmodel)) {
711
- return kmodel;
712
- }
713
- else {
714
- throw new Error(`[@ktjs/core error] k-model data must be a KTRef object, please use 'ref(...)' to wrap it.`);
715
- }
716
- }
717
- return ref(defaultValue);
718
- };
719
- const $refSetter = (props, node) => (props.ref.value = node);
720
- /**
721
- * Whether `props.ref` is a `KTRef` only needs to be checked in the initial render
722
- */
723
- const $initRef = (props, node) => {
724
- if (!('ref' in props)) {
725
- return $emptyFn;
726
- }
727
- const r = props.ref;
728
- if (isRef(r)) {
729
- r.value = node;
730
- return $refSetter;
731
- }
732
- else {
733
- throw new Error('[@ktjs/core error] Fragment: ref must be a KTRef');
734
- }
735
- };
736
204
 
737
- /**
738
- * Register a reactive effect with options.
739
- * @param effectFn The effect function to run when dependencies change
740
- * @param reactives The reactive dependencies
741
- * @param options Effect options: lazy, onCleanup, debugName
742
- * @returns stop function to remove all listeners
743
- */
744
205
  function effect(effectFn, reactives, options) {
745
- const { lazy = false, onCleanup = $emptyFn, debugName = '' } = Object(options);
746
- const listenerKeys = [];
747
- let active = true;
206
+ const {lazy: lazy = !1, onCleanup: onCleanup = $emptyFn, debugName: debugName = ""} = Object(options), listenerKeys = [];
207
+ let active = !0;
748
208
  const run = () => {
749
- if (!active) {
750
- return;
751
- }
752
- // cleanup before rerun
753
- onCleanup();
754
- try {
755
- effectFn();
756
- }
757
- catch (err) {
758
- console.debug('[@ktjs/core debug]','effect error:', debugName, err);
209
+ if (active) {
210
+ onCleanup();
211
+ try {
212
+ effectFn();
213
+ } catch (err) {
214
+ console.debug("[@ktjs/core debug]", "effect error:", debugName, err);
215
+ }
759
216
  }
760
217
  };
761
- // subscribe to dependencies
762
- for (let i = 0; i < reactives.length; i++) {
763
- listenerKeys[i] = reactives[i].addOnChange(run);
764
- }
765
- // auto run unless lazy
766
- if (!lazy) {
767
- run();
768
- }
769
- // stop function
770
- return () => {
771
- if (!active) {
772
- return;
773
- }
774
- active = false;
775
- for (let i = 0; i < reactives.length; i++) {
776
- reactives[i].removeOnChange(listenerKeys[i]);
218
+ for (let i = 0; i < reactives.length; i++) listenerKeys[i] = i, reactives[i].addOnChange(run, i);
219
+ return lazy || run(), () => {
220
+ if (active) {
221
+ active = !1;
222
+ for (let i = 0; i < reactives.length; i++) reactives[i].removeOnChange(listenerKeys[i]);
223
+ onCleanup();
777
224
  }
778
- // final cleanup
779
- onCleanup();
780
225
  };
781
226
  }
782
227
 
783
- const toReactive = (value, onChange) => {
784
- if (isKT(value)) {
785
- if (onChange) {
786
- value.addOnChange(onChange);
787
- }
788
- return value;
789
- }
790
- else {
791
- return ref(value, onChange);
792
- }
228
+ KTReactive.prototype.map = function(calculator, dependencies) {
229
+ return new KTComputed(() => calculator(this._value), dependencies ? [ this, ...dependencies ] : [ this ]);
793
230
  };
794
- /**
795
- * Extracts the value from a KTReactive, or returns the value directly if it's not reactive.
796
- */
231
+
232
+ const toReactive = value => isKT(value) ? value : ref(value);
233
+
797
234
  function dereactive(value) {
798
235
  return isKT(value) ? value.value : value;
799
236
  }
800
237
 
801
238
  function applyKModel(element, valueRef) {
802
- if (!isKT(valueRef)) {
803
- throw new Error('[@ktjs/core error] k-model value must be a KTRef.');
804
- }
805
- if (element.tagName === 'INPUT') {
806
- if (element.type === 'radio' || element.type === 'checkbox') {
807
- $applyModel(element, valueRef, 'checked', 'change');
808
- return;
809
- }
810
- if (element.type === 'number') {
811
- $applyModel(element, valueRef, 'checked', 'change', Number);
812
- return;
813
- }
814
- if (element.type === 'date') {
815
- $applyModel(element, valueRef, 'checked', 'change', (v) => new Date(v));
816
- return;
817
- }
818
- $applyModel(element, valueRef, 'value', 'input');
819
- }
820
- else if (element.tagName === 'SELECT') {
821
- $applyModel(element, valueRef, 'value', 'change');
822
- }
823
- else if (element.tagName === 'TEXTAREA') {
824
- $applyModel(element, valueRef, 'value', 'input');
825
- }
826
- else {
827
- console.warn('[@ktjs/core warn]','not supported element for k-model:');
828
- }
239
+ if (!isKT(valueRef)) throw new Error("[@ktjs/core error] k-model value must be a KTRef.");
240
+ if ("INPUT" === element.tagName) {
241
+ if ("radio" === element.type || "checkbox" === element.type) return void $applyModel(element, valueRef, "checked", "change");
242
+ if ("number" === element.type) return void $applyModel(element, valueRef, "checked", "change", Number);
243
+ if ("date" === element.type) return void $applyModel(element, valueRef, "checked", "change", v => new Date(v));
244
+ $applyModel(element, valueRef, "value", "input");
245
+ } else "SELECT" === element.tagName ? $applyModel(element, valueRef, "value", "change") : "TEXTAREA" === element.tagName ? $applyModel(element, valueRef, "value", "input") : console.warn("[@ktjs/core warn]", "not supported element for k-model:");
829
246
  }
830
247
 
831
248
  /**
@@ -838,473 +255,228 @@ function applyKModel(element, valueRef) {
838
255
  * ## About
839
256
  * @package @ktjs/core
840
257
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
841
- * @version 0.32.5 (Last Update: 2026.03.19 20:31:46.571)
258
+ * @version 0.33.1 (Last Update: 2026.03.21 23:05:09.100)
842
259
  * @license MIT
843
260
  * @link https://github.com/baendlorel/kt.js
844
261
  * @link https://baendlorel.github.io/ Welcome to my site!
845
262
  * @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
846
263
  * @copyright Copyright (c) 2026 Kasukabe Tsumugi. All rights reserved.
847
- */
848
- const h = (tag, attr, content) => {
849
- if (typeof tag !== 'string') {
850
- throw new Error('[@ktjs/core error] tagName must be a string.');
851
- }
852
- // * start creating the element
264
+ */ const h = (tag, attr, content) => {
265
+ if ("string" != typeof tag) throw new Error("[@ktjs/core error] tagName must be a string.");
853
266
  const element = document.createElement(tag);
854
- if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
855
- applyKModel(element, attr['k-model']);
856
- }
857
- // * Handle content
858
- applyAttr(element, attr);
859
- applyContent(element, content);
860
- return element;
861
- };
862
- const svg$1 = (tag, attr, content) => {
863
- if (typeof tag !== 'string') {
864
- throw new Error('[@ktjs/core error] tagName must be a string.');
865
- }
866
- // * start creating the element
867
- const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
868
- // * Handle content
869
- applyAttr(element, attr);
870
- applyContent(element, content);
871
- if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
872
- applyKModel(element, attr['k-model']);
873
- }
874
- return element;
875
- };
876
- const mathml$1 = (tag, attr, content) => {
877
- if (typeof tag !== 'string') {
878
- throw new Error('[@ktjs/core error] tagName must be a string.');
879
- }
880
- // * start creating the element
881
- const element = document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
882
- // * Handle content
883
- applyAttr(element, attr);
884
- applyContent(element, content);
885
- if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
886
- applyKModel(element, attr['k-model']);
887
- }
888
- return element;
267
+ return "object" == typeof attr && null !== attr && "k-model" in attr && applyKModel(element, attr["k-model"]),
268
+ applyAttr(element, attr), applyContent(element, content), element;
269
+ }, svg$1 = (tag, attr, content) => {
270
+ if ("string" != typeof tag) throw new Error("[@ktjs/core error] tagName must be a string.");
271
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
272
+ return applyAttr(element, attr), applyContent(element, content), "object" == typeof attr && null !== attr && "k-model" in attr && applyKModel(element, attr["k-model"]),
273
+ element;
274
+ }, mathml$1 = (tag, attr, content) => {
275
+ if ("string" != typeof tag) throw new Error("[@ktjs/core error] tagName must be a string.");
276
+ const element = document.createElementNS("http://www.w3.org/1998/Math/MathML", tag);
277
+ return applyAttr(element, attr), applyContent(element, content), "object" == typeof attr && null !== attr && "k-model" in attr && applyKModel(element, attr["k-model"]),
278
+ element;
889
279
  };
890
280
 
891
- const FRAGMENT_MOUNT_PATCHED = '__kt_fragment_mount_patched__';
892
- const FRAGMENT_MOUNT = '__kt_fragment_mount__';
893
- if (typeof Node !== 'undefined' && !globalThis[FRAGMENT_MOUNT_PATCHED]) {
894
- globalThis[FRAGMENT_MOUNT_PATCHED] = true;
281
+ if ("undefined" != typeof Node && !globalThis.__kt_fragment_mount_patched__) {
282
+ globalThis.__kt_fragment_mount_patched__ = !0;
895
283
  const originAppendChild = Node.prototype.appendChild;
896
- Node.prototype.appendChild = function (node) {
897
- const result = originAppendChild.call(this, node);
898
- const mount = node[FRAGMENT_MOUNT];
899
- if (typeof mount === 'function') {
900
- mount();
901
- }
902
- return result;
284
+ Node.prototype.appendChild = function(node) {
285
+ const result = originAppendChild.call(this, node), mount = node.__kt_fragment_mount__;
286
+ return "function" == typeof mount && mount(), result;
903
287
  };
904
288
  const originInsertBefore = Node.prototype.insertBefore;
905
- Node.prototype.insertBefore = function (node, child) {
906
- const result = originInsertBefore.call(this, node, child);
907
- const mount = node[FRAGMENT_MOUNT];
908
- if (typeof mount === 'function') {
909
- mount();
910
- }
911
- return result;
289
+ Node.prototype.insertBefore = function(node, child) {
290
+ const result = originInsertBefore.call(this, node, child), mount = node.__kt_fragment_mount__;
291
+ return "function" == typeof mount && mount(), result;
912
292
  };
913
293
  }
914
- /**
915
- * Fragment - Container component for managing arrays of child elements
916
- *
917
- * Features:
918
- * 1. Returns a comment anchor node, child elements are inserted after the anchor
919
- * 2. Supports reactive arrays, automatically updates DOM when array changes
920
- * 3. Basic version uses simple replacement algorithm (remove all old elements, insert all new elements)
921
- * 4. Future enhancement: key-based optimization
922
- *
923
- * Usage example:
924
- * ```tsx
925
- * const children = ref([<div>A</div>, <div>B</div>]);
926
- * const fragment = <Fragment children={children} />;
927
- * document.body.appendChild(fragment);
928
- *
929
- * // Automatic update
930
- * children.value = [<div>C</div>, <div>D</div>];
931
- * ```
932
- */
933
- function Fragment$1(props) {
934
- const elements = [];
935
- const anchor = document.createComment('kt-fragment');
936
- let inserted = false;
937
- let observer;
938
- const redraw = () => {
939
- const newElements = childrenRef.value;
940
- const parent = anchor.parentNode;
941
- if (!parent) {
942
- elements.length = 0;
943
- for (let i = 0; i < newElements.length; i++) {
944
- elements.push(newElements[i]);
945
- }
946
- anchor.__kt_fragment_list__ = elements;
947
- return;
948
- }
949
- for (let i = 0; i < elements.length; i++) {
950
- elements[i].remove();
951
- }
952
- const fragment = document.createDocumentFragment();
953
- elements.length = 0;
954
- for (let i = 0; i < newElements.length; i++) {
955
- const element = newElements[i];
956
- elements.push(element);
957
- fragment.appendChild(element);
958
- }
959
- parent.insertBefore(fragment, anchor.nextSibling);
960
- inserted = true;
961
- delete anchor[FRAGMENT_MOUNT];
962
- observer?.disconnect();
963
- observer = undefined;
964
- anchor.__kt_fragment_list__ = elements;
965
- };
966
- const childrenRef = toReactive(props.children, redraw);
967
- const renderInitial = () => {
968
- const current = childrenRef.value;
969
- elements.length = 0;
970
- const fragment = document.createDocumentFragment();
971
- for (let i = 0; i < current.length; i++) {
972
- const element = current[i];
973
- elements.push(element);
974
- fragment.appendChild(element);
975
- }
976
- anchor.__kt_fragment_list__ = elements;
977
- const parent = anchor.parentNode;
978
- if (parent && !inserted) {
979
- parent.insertBefore(fragment, anchor.nextSibling);
980
- inserted = true;
981
- }
982
- };
983
- renderInitial();
984
- anchor[FRAGMENT_MOUNT] = () => {
985
- if (!inserted && anchor.parentNode) {
986
- redraw();
987
- }
988
- };
989
- observer = new MutationObserver(() => {
990
- if (anchor.parentNode && !inserted) {
991
- redraw();
992
- observer?.disconnect();
993
- observer = undefined;
994
- }
995
- });
996
- observer.observe(document.body, { childList: true, subtree: true });
997
- $initRef(props, anchor);
998
- return anchor;
999
- }
1000
- /**
1001
- * Convert KTRawContent to HTMLElement array
1002
- */
1003
- function convertChildrenToElements(children) {
1004
- const elements = [];
1005
- const processChild = (child) => {
1006
- if (child === undefined || child === null || child === false || child === true) {
1007
- // Ignore null, undefined, false, true
1008
- return;
1009
- }
1010
- if ($isArray(child)) {
1011
- // Recursively process array
1012
- $forEach(child, processChild);
1013
- return;
1014
- }
1015
- if (typeof child === 'string' || typeof child === 'number') {
1016
- const span = document.createElement('span');
1017
- span.textContent = String(child);
1018
- elements.push(span);
1019
- return;
1020
- }
1021
- if (child instanceof HTMLElement) {
1022
- elements.push(child);
1023
- return;
1024
- }
1025
- if (isKT(child)) {
1026
- processChild(child.value);
1027
- return;
1028
- }
1029
- console.warn('Fragment: unsupported child type', child);
1030
- };
1031
- processChild(children);
1032
- return elements;
1033
- }
1034
294
 
1035
- const jsxh = (tag, props) => (typeof tag === 'function' ? tag(props) : h(tag, props, props.children));
1036
- const placeholder = (data) => document.createComment(data);
295
+ const jsxh = (tag, props) => "function" == typeof tag ? tag(props) : h(tag, props, props.children), placeholder = data => document.createComment(data);
1037
296
 
1038
297
  function create(creator, tag, props) {
1039
- if (props.ref && isComputed(props.ref)) {
1040
- throw new Error('[@ktjs/core error] Cannot assign a computed value to an element.');
1041
- }
298
+ if (props.ref && isComputed(props.ref)) throw new Error("[@ktjs/core error] Cannot assign a computed value to an element.");
1042
299
  const el = creator(tag, props, props.children);
1043
- $initRef(props, el);
1044
- return el;
300
+ return $initRef(props, el), el;
1045
301
  }
1046
- const jsx = (tag, props) => create(jsxh, tag, props);
1047
- const svg = (tag, props) => create(svg$1, tag, props);
1048
- const mathml = (tag, props) => create(mathml$1, tag, props);
1049
- /**
1050
- * Fragment support - returns an array of children
1051
- * Enhanced Fragment component that manages arrays of elements
1052
- */
302
+
303
+ const jsx = (tag, props) => create(jsxh, tag, props), svg = (tag, props) => create(svg$1, tag, props), mathml = (tag, props) => create(mathml$1, tag, props);
304
+
1053
305
  function Fragment(props) {
1054
- const { children } = props ?? {};
1055
- if (!children) {
1056
- return placeholder('kt-fragment-empty');
1057
- }
1058
- const elements = convertChildrenToElements(children);
1059
- return Fragment$1({ children: elements });
306
+ const {children: children} = props ?? {};
307
+ if (!children) return placeholder("kt-fragment-empty");
308
+ const elements = function(children) {
309
+ const elements = [], processChild = child => {
310
+ if (null != child && !1 !== child && !0 !== child) if ($isArray(child)) $forEach(child, processChild); else {
311
+ if ("string" == typeof child || "number" == typeof child) {
312
+ const span = document.createElement("span");
313
+ return span.textContent = String(child), void elements.push(span);
314
+ }
315
+ if (child instanceof HTMLElement) elements.push(child); else {
316
+ if (!isKT(child)) throw console.warn("[@ktjs/core warn]", "Fragment: unsupported child type", child),
317
+ new Error("Fragment: unsupported child type");
318
+ processChild(child.value);
319
+ }
320
+ }
321
+ };
322
+ return processChild(children), elements;
323
+ }(children);
324
+ return function(props) {
325
+ const elements = [], anchor = document.createComment("kt-fragment");
326
+ let observer, inserted = !1;
327
+ const redraw = () => {
328
+ const newElements = childrenRef.value, parent = anchor.parentNode;
329
+ if (!parent) {
330
+ elements.length = 0;
331
+ for (let i = 0; i < newElements.length; i++) elements.push(newElements[i]);
332
+ return void (anchor.__kt_fragment_list__ = elements);
333
+ }
334
+ for (let i = 0; i < elements.length; i++) elements[i].remove();
335
+ const fragment = document.createDocumentFragment();
336
+ elements.length = 0;
337
+ for (let i = 0; i < newElements.length; i++) {
338
+ const element = newElements[i];
339
+ elements.push(element), fragment.appendChild(element);
340
+ }
341
+ parent.insertBefore(fragment, anchor.nextSibling), inserted = !0, delete anchor.__kt_fragment_mount__,
342
+ observer?.disconnect(), observer = void 0, anchor.__kt_fragment_list__ = elements;
343
+ }, childrenRef = toReactive(props.children).addOnChange(redraw);
344
+ return (() => {
345
+ const current = childrenRef.value;
346
+ elements.length = 0;
347
+ const fragment = document.createDocumentFragment();
348
+ for (let i = 0; i < current.length; i++) {
349
+ const element = current[i];
350
+ elements.push(element), fragment.appendChild(element);
351
+ }
352
+ anchor.__kt_fragment_list__ = elements;
353
+ const parent = anchor.parentNode;
354
+ parent && !inserted && (parent.insertBefore(fragment, anchor.nextSibling), inserted = !0);
355
+ })(), anchor.__kt_fragment_mount__ = () => {
356
+ !inserted && anchor.parentNode && redraw();
357
+ }, observer = new MutationObserver(() => {
358
+ anchor.parentNode && !inserted && (redraw(), observer?.disconnect(), observer = void 0);
359
+ }), observer.observe(document.body, {
360
+ childList: !0,
361
+ subtree: !0
362
+ }), $initRef(props, anchor), anchor;
363
+ }({
364
+ children: elements
365
+ });
1060
366
  }
1061
- /**
1062
- * JSX Development runtime - same as jsx but with additional dev checks
1063
- */
1064
- const jsxDEV = (...args) => {
1065
- // console.log('JSX DEV called:', ...args);
1066
- // console.log('children', (args[1] as any)?.children);
1067
- return jsx(...args);
1068
- };
1069
- /**
1070
- * JSX runtime for React 17+ automatic runtime
1071
- * This is called when using jsx: "react-jsx" or "react-jsxdev"
1072
- */
1073
- const jsxs = jsx;
367
+
368
+ const jsxDEV = (...args) => jsx(...args), jsxs = jsx;
1074
369
 
1075
370
  function KTAsync(props) {
1076
371
  const raw = props.component(props);
1077
- let comp = props.skeleton ?? document.createComment('ktjs-suspense-placeholder');
1078
- if ($isThenable(raw)) {
1079
- raw.then((resolved) => comp.replaceWith(resolved));
1080
- }
1081
- else {
1082
- comp = raw;
1083
- }
1084
- return comp;
372
+ let comp = props.skeleton ?? document.createComment("ktjs-suspense-placeholder");
373
+ return $isThenable(raw) ? raw.then(resolved => comp.replaceWith(resolved)) : comp = raw,
374
+ comp;
1085
375
  }
1086
376
 
1087
- // todo 对于template标签的for和if,会编译为fragment,可特殊处理,让它们保持原样
1088
- /**
1089
- * KTFor - List rendering component with key-based optimization
1090
- * Returns a Comment anchor node with rendered elements in __kt_for_list__
1091
- */
1092
377
  function KTFor(props) {
1093
- const redraw = () => {
1094
- const newList = listRef.value;
1095
- const parent = anchor.parentNode;
378
+ const {key: currentKey = item => item, map: currentMap = $identity} = props, listRef = toReactive(props.list).addOnChange(() => {
379
+ const newList = listRef.value, parent = anchor.parentNode;
1096
380
  if (!parent) {
1097
- // If not in DOM yet, just rebuild the list
1098
381
  const newElements = [];
1099
382
  nodeMap.clear();
1100
383
  for (let index = 0; index < newList.length; index++) {
1101
- const item = newList[index];
1102
- const itemKey = currentKey(item, index, newList);
1103
- const node = currentMap(item, index, newList);
1104
- nodeMap.set(itemKey, node);
1105
- newElements.push(node);
384
+ const item = newList[index], itemKey = currentKey(item, index, newList), node = currentMap(item, index, newList);
385
+ nodeMap.set(itemKey, node), newElements.push(node);
1106
386
  }
1107
- anchor.__kt_for_list__ = newElements;
1108
- return anchor;
387
+ return anchor.__kt_for_list__ = newElements, anchor;
1109
388
  }
1110
- const oldLength = anchor.__kt_for_list__.length;
1111
- const newLength = newList.length;
1112
- // Fast path: empty list
1113
- if (newLength === 0) {
1114
- nodeMap.forEach((node) => node.remove());
1115
- nodeMap.clear();
1116
- anchor.__kt_for_list__ = [];
1117
- return anchor;
1118
- }
1119
- // Fast path: all new items
1120
- if (oldLength === 0) {
1121
- const newElements = [];
1122
- const fragment = document.createDocumentFragment();
389
+ const oldLength = anchor.__kt_for_list__.length, newLength = newList.length;
390
+ if (0 === newLength) return nodeMap.forEach(node => node.remove()), nodeMap.clear(),
391
+ anchor.__kt_for_list__ = [], anchor;
392
+ if (0 === oldLength) {
393
+ const newElements = [], fragment = document.createDocumentFragment();
1123
394
  for (let i = 0; i < newLength; i++) {
1124
- const item = newList[i];
1125
- const itemKey = currentKey(item, i, newList);
1126
- const node = currentMap(item, i, newList);
1127
- nodeMap.set(itemKey, node);
1128
- newElements.push(node);
1129
- fragment.appendChild(node);
395
+ const item = newList[i], itemKey = currentKey(item, i, newList), node = currentMap(item, i, newList);
396
+ nodeMap.set(itemKey, node), newElements.push(node), fragment.appendChild(node);
1130
397
  }
1131
- parent.insertBefore(fragment, anchor.nextSibling);
1132
- anchor.__kt_for_list__ = newElements;
1133
- return anchor;
398
+ return parent.insertBefore(fragment, anchor.nextSibling), anchor.__kt_for_list__ = newElements,
399
+ anchor;
1134
400
  }
1135
- // Build key index map and new elements array in one pass
1136
- const newKeyToNewIndex = new Map();
1137
- const newElements = new Array(newLength);
1138
- let maxNewIndexSoFar = 0;
1139
- let moved = false;
401
+ const newKeyToNewIndex = new Map, newElements = new Array(newLength);
402
+ let maxNewIndexSoFar = 0, moved = !1;
1140
403
  for (let i = 0; i < newLength; i++) {
1141
- const item = newList[i];
1142
- const itemKey = currentKey(item, i, newList);
1143
- newKeyToNewIndex.set(itemKey, i);
1144
- if (nodeMap.has(itemKey)) {
1145
- // Reuse existing node
404
+ const item = newList[i], itemKey = currentKey(item, i, newList);
405
+ if (newKeyToNewIndex.set(itemKey, i), nodeMap.has(itemKey)) {
1146
406
  const node = nodeMap.get(itemKey);
1147
- newElements[i] = node;
1148
- // Track if items moved
1149
- if (i < maxNewIndexSoFar) {
1150
- moved = true;
1151
- }
1152
- else {
1153
- maxNewIndexSoFar = i;
1154
- }
1155
- }
1156
- else {
1157
- // Create new node
1158
- newElements[i] = currentMap(item, i, newList);
1159
- }
407
+ newElements[i] = node, i < maxNewIndexSoFar ? moved = !0 : maxNewIndexSoFar = i;
408
+ } else newElements[i] = currentMap(item, i, newList);
1160
409
  }
1161
- // Remove nodes not in new list
1162
410
  const toRemove = [];
1163
411
  nodeMap.forEach((node, key) => {
1164
- if (!newKeyToNewIndex.has(key)) {
1165
- toRemove.push(node);
1166
- }
412
+ newKeyToNewIndex.has(key) || toRemove.push(node);
1167
413
  });
1168
- for (let i = 0; i < toRemove.length; i++) {
1169
- toRemove[i].remove();
1170
- }
1171
- // Update DOM with minimal operations
414
+ for (let i = 0; i < toRemove.length; i++) toRemove[i].remove();
1172
415
  if (moved) {
1173
- // Use longest increasing subsequence to minimize moves
1174
- const seq = getSequence(newElements.map((el, i) => (nodeMap.has(currentKey(newList[i], i, newList)) ? i : -1)));
1175
- let j = seq.length - 1;
1176
- let anchor = null;
1177
- // Traverse from end to start for stable insertions
1178
- for (let i = newLength - 1; i >= 0; i--) {
1179
- const node = newElements[i];
1180
- if (j < 0 || i !== seq[j]) {
1181
- // Node needs to be moved or inserted
1182
- if (anchor) {
1183
- parent.insertBefore(node, anchor);
416
+ const seq = function(arr) {
417
+ const p = arr.slice(), result = [ 0 ];
418
+ let i, j, u, v, c;
419
+ const len = arr.length;
420
+ for (i = 0; i < len; i++) {
421
+ const arrI = arr[i];
422
+ if (-1 !== arrI) if (j = result[result.length - 1], arr[j] < arrI) p[i] = j, result.push(i); else {
423
+ for (u = 0, v = result.length - 1; u < v; ) c = (u + v) / 2 | 0, arr[result[c]] < arrI ? u = c + 1 : v = c;
424
+ arrI < arr[result[u]] && (u > 0 && (p[i] = result[u - 1]), result[u] = i);
1184
425
  }
1185
- else {
1186
- // Insert at end
1187
- let nextSibling = anchor.nextSibling;
1188
- let temp = nextSibling;
1189
- while (temp && newElements.includes(temp)) {
1190
- temp = temp.nextSibling;
1191
- }
1192
- parent.insertBefore(node, temp);
1193
- }
1194
- }
1195
- else {
1196
- j--;
1197
426
  }
427
+ u = result.length, v = result[u - 1];
428
+ for (;u-- > 0; ) result[u] = v, v = p[v];
429
+ return result;
430
+ }(newElements.map((el, i) => nodeMap.has(currentKey(newList[i], i, newList)) ? i : -1));
431
+ let j = seq.length - 1, anchor = null;
432
+ for (let i = newLength - 1; i >= 0; i--) {
433
+ const node = newElements[i];
434
+ if (j < 0 || i !== seq[j]) if (anchor) parent.insertBefore(node, anchor); else {
435
+ let temp = anchor.nextSibling;
436
+ for (;temp && newElements.includes(temp); ) temp = temp.nextSibling;
437
+ parent.insertBefore(node, temp);
438
+ } else j--;
1198
439
  anchor = node;
1199
440
  }
1200
- }
1201
- else {
1202
- // No moves needed, just insert new nodes
441
+ } else {
1203
442
  let currentNode = anchor.nextSibling;
1204
443
  for (let i = 0; i < newLength; i++) {
1205
444
  const node = newElements[i];
1206
- if (currentNode !== node) {
1207
- parent.insertBefore(node, currentNode);
1208
- }
1209
- else {
1210
- currentNode = currentNode.nextSibling;
1211
- }
445
+ currentNode !== node ? parent.insertBefore(node, currentNode) : currentNode = currentNode.nextSibling;
1212
446
  }
1213
447
  }
1214
- // Update maps
1215
448
  nodeMap.clear();
1216
449
  for (let i = 0; i < newLength; i++) {
1217
450
  const itemKey = currentKey(newList[i], i, newList);
1218
451
  nodeMap.set(itemKey, newElements[i]);
1219
452
  }
1220
- anchor.__kt_for_list__ = newElements;
1221
- return anchor;
1222
- };
1223
- const { key: currentKey = (item) => item, map: currentMap = $identity } = props;
1224
- const listRef = toReactive(props.list, redraw);
1225
- const anchor = document.createComment('kt-for');
1226
- // Map to track rendered nodes by key
1227
- const nodeMap = new Map();
1228
- // Render initial list
1229
- const elements = [];
453
+ return anchor.__kt_for_list__ = newElements, anchor;
454
+ }), anchor = document.createComment("kt-for"), nodeMap = new Map, elements = [];
1230
455
  for (let index = 0; index < listRef.value.length; index++) {
1231
- const item = listRef.value[index];
1232
- const itemKey = currentKey(item, index, listRef.value);
1233
- const node = currentMap(item, index, listRef.value);
1234
- nodeMap.set(itemKey, node);
1235
- elements.push(node);
1236
- }
1237
- anchor.__kt_for_list__ = elements;
1238
- $initRef(props, anchor);
1239
- return anchor;
1240
- }
1241
- // Longest Increasing Subsequence algorithm (optimized for diff)
1242
- function getSequence(arr) {
1243
- const p = arr.slice();
1244
- const result = [0];
1245
- let i, j, u, v, c;
1246
- const len = arr.length;
1247
- for (i = 0; i < len; i++) {
1248
- const arrI = arr[i];
1249
- if (arrI === -1)
1250
- continue;
1251
- j = result[result.length - 1];
1252
- if (arr[j] < arrI) {
1253
- p[i] = j;
1254
- result.push(i);
1255
- continue;
1256
- }
1257
- u = 0;
1258
- v = result.length - 1;
1259
- while (u < v) {
1260
- c = ((u + v) / 2) | 0;
1261
- if (arr[result[c]] < arrI) {
1262
- u = c + 1;
1263
- }
1264
- else {
1265
- v = c;
1266
- }
1267
- }
1268
- if (arrI < arr[result[u]]) {
1269
- if (u > 0) {
1270
- p[i] = result[u - 1];
1271
- }
1272
- result[u] = i;
1273
- }
456
+ const item = listRef.value[index], itemKey = currentKey(item, index, listRef.value), node = currentMap(item, index, listRef.value);
457
+ nodeMap.set(itemKey, node), elements.push(node);
1274
458
  }
1275
- u = result.length;
1276
- v = result[u - 1];
1277
- while (u-- > 0) {
1278
- result[u] = v;
1279
- v = p[v];
1280
- }
1281
- return result;
459
+ return anchor.__kt_for_list__ = elements, $initRef(props, anchor), anchor;
1282
460
  }
1283
461
 
1284
462
  function KTConditional(condition, tagIf, propsIf, tagElse, propsElse) {
1285
- if (!isKT(condition)) {
1286
- return condition ? jsxh(tagIf, propsIf) : tagElse ? jsxh(tagElse, propsElse) : placeholder('kt-conditional');
1287
- }
463
+ if (!isKT(condition)) return condition ? jsxh(tagIf, propsIf) : tagElse ? jsxh(tagElse, propsElse) : placeholder("kt-conditional");
1288
464
  if (tagElse) {
1289
465
  let current = condition.value ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse);
1290
- condition.addOnChange((newValue) => {
466
+ return condition.addOnChange(newValue => {
1291
467
  const old = current;
1292
- current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse);
1293
- old.replaceWith(current);
1294
- });
1295
- return current;
468
+ current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse), old.replaceWith(current);
469
+ }), current;
1296
470
  }
1297
- else {
1298
- const dummy = placeholder('kt-conditional');
471
+ {
472
+ const dummy = placeholder("kt-conditional");
1299
473
  let current = condition.value ? jsxh(tagIf, propsIf) : dummy;
1300
- condition.addOnChange((newValue) => {
474
+ return condition.addOnChange(newValue => {
1301
475
  const old = current;
1302
- current = newValue ? jsxh(tagIf, propsIf) : dummy;
1303
- old.replaceWith(current);
1304
- });
1305
- return current;
476
+ current = newValue ? jsxh(tagIf, propsIf) : dummy, old.replaceWith(current);
477
+ }), current;
1306
478
  }
1307
479
  }
1308
480
 
1309
- export { $initRef, $modelOrRef, Fragment, KTArrayRef, KTAsync, KTComputed, KTConditional, KTDateRef, KTFor, KTMapRef, KTSetRef, KTWeakMapRef, KTWeakSetRef, applyAttr, autoRef, computed, h as createElement, mathml$1 as createMathMLElement, svg$1 as createSVGElement, dereactive, effect, h, isArrayRef, isComputed, isDateRef, isKT, isMapRef, isRef, isSetRef, isWeakMapRef, isWeakSetRef, jsx, jsxDEV, jsxs, mathml, mathml as mathmlRuntime, ref, svg, svg as svgRuntime, toReactive };
481
+ export { $initRef, $modelOrRef, Fragment, KTAsync, KTComputed, KTConditional, KTFor, KTRef, applyAttr, computed, h as createElement, mathml$1 as createMathMLElement, svg$1 as createSVGElement, dereactive, effect, h, isComputed, isKT, isRef, jsx, jsxDEV, jsxs, mathml, mathml as mathmlRuntime, ref, svg, svg as svgRuntime, toReactive };
1310
482
  //# sourceMappingURL=index.mjs.map