@ktjs/core 0.32.4 → 0.33.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.
- package/README.md +38 -2
- package/dist/index.d.ts +113 -317
- package/dist/index.mjs +143 -442
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $isArray, $isThenable, $isNode, $
|
|
1
|
+
import { $isArray, $isThenable, $isNode, $emptyFn, $is, $applyModel, $forEach, $identity } from '@ktjs/shared';
|
|
2
2
|
|
|
3
3
|
const isKT = (obj) => obj?.isKT;
|
|
4
4
|
const isRef = (obj) => {
|
|
@@ -7,15 +7,9 @@ const isRef = (obj) => {
|
|
|
7
7
|
if (obj.ktType === undefined) {
|
|
8
8
|
return false;
|
|
9
9
|
}
|
|
10
|
-
return obj.ktType
|
|
10
|
+
return obj.ktType === 3 /* KTReactiveType.Ref */;
|
|
11
11
|
};
|
|
12
|
-
const
|
|
13
|
-
const isMapRef = (obj) => obj?.ktType === 4 /* KTReactiveType.MapRef */;
|
|
14
|
-
const isSetRef = (obj) => obj?.ktType === 5 /* KTReactiveType.SetRef */;
|
|
15
|
-
const isWeakMapRef = (obj) => obj?.ktType === 6 /* KTReactiveType.WeakMapRef */;
|
|
16
|
-
const isWeakSetRef = (obj) => obj?.ktType === 7 /* KTReactiveType.WeakSetRef */;
|
|
17
|
-
const isDateRef = (obj) => obj?.ktType === 8 /* KTReactiveType.DateRef */;
|
|
18
|
-
const isComputed = (obj) => obj?.ktType === 1 /* KTReactiveType.Computed */;
|
|
12
|
+
const isComputed = (obj) => obj?.ktType === 2 /* KTReactiveType.Computed */;
|
|
19
13
|
|
|
20
14
|
const booleanHandler = (element, key, value) => {
|
|
21
15
|
if (key in element) {
|
|
@@ -215,22 +209,14 @@ const IdGenerator = {
|
|
|
215
209
|
_refOnChangeId: 1,
|
|
216
210
|
get refOnChangeId() {
|
|
217
211
|
return this._refOnChangeId++;
|
|
218
|
-
},
|
|
219
|
-
_computedOnChangeId: 1,
|
|
220
|
-
get computedOnChangeId() {
|
|
221
|
-
return this._computedOnChangeId++;
|
|
222
212
|
}};
|
|
223
213
|
|
|
224
|
-
class
|
|
214
|
+
class KTReactive {
|
|
225
215
|
/**
|
|
226
216
|
* Indicates that this is a KTRef instance
|
|
227
217
|
*/
|
|
228
218
|
isKT = true;
|
|
229
|
-
ktType = 1 /* KTReactiveType.
|
|
230
|
-
/**
|
|
231
|
-
* @internal
|
|
232
|
-
*/
|
|
233
|
-
_calculator;
|
|
219
|
+
ktType = 1 /* KTReactiveType.Reative */;
|
|
234
220
|
/**
|
|
235
221
|
* @internal
|
|
236
222
|
*/
|
|
@@ -238,146 +224,93 @@ class KTComputed {
|
|
|
238
224
|
/**
|
|
239
225
|
* @internal
|
|
240
226
|
*/
|
|
241
|
-
|
|
227
|
+
_changeHandlers = new Map();
|
|
242
228
|
/**
|
|
243
229
|
* @internal
|
|
244
230
|
*/
|
|
245
231
|
_emit(newValue, oldValue, handlerKeys) {
|
|
246
232
|
if (handlerKeys) {
|
|
247
233
|
for (let i = 0; i < handlerKeys.length; i++) {
|
|
248
|
-
this.
|
|
234
|
+
this._changeHandlers.get(handlerKeys[i])?.(newValue, oldValue);
|
|
249
235
|
}
|
|
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());
|
|
236
|
+
return this;
|
|
276
237
|
}
|
|
238
|
+
this._changeHandlers.forEach((c) => c(newValue, oldValue));
|
|
239
|
+
return this;
|
|
277
240
|
}
|
|
278
|
-
constructor(
|
|
279
|
-
this.
|
|
280
|
-
this.
|
|
281
|
-
this._subscribe(reactives);
|
|
241
|
+
constructor(_value) {
|
|
242
|
+
this._value = _value;
|
|
243
|
+
this._changeHandlers = new Map();
|
|
282
244
|
}
|
|
283
245
|
/**
|
|
284
246
|
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
247
|
+
* - Use `.mutable` to modify the value.
|
|
248
|
+
* @readonly
|
|
285
249
|
*/
|
|
286
250
|
get value() {
|
|
287
251
|
return this._value;
|
|
288
252
|
}
|
|
289
253
|
set value(_newValue) {
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Force listeners to run once with the latest computed result.
|
|
294
|
-
*/
|
|
295
|
-
notify(handlerKeys) {
|
|
296
|
-
this._recalculate(true, handlerKeys);
|
|
254
|
+
// Only allow KTRef to be set.
|
|
297
255
|
}
|
|
298
256
|
/**
|
|
299
|
-
*
|
|
257
|
+
* Force all listeners to run even when reference identity has not changed.
|
|
258
|
+
* Useful for in-place array/object mutations.
|
|
259
|
+
* - Is implemented differently in `KTRef` and `KTComputed`
|
|
300
260
|
*/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (handlerKeys) {
|
|
304
|
-
this._emit(this._value, this._value, handlerKeys);
|
|
305
|
-
}
|
|
306
|
-
return this._value;
|
|
261
|
+
notify(..._args) {
|
|
262
|
+
throw new Error('This is meant to be override in ref.ts and computed.ts');
|
|
307
263
|
}
|
|
308
|
-
|
|
309
|
-
|
|
264
|
+
map(..._args) {
|
|
265
|
+
throw new Error('This is meant to be override in computed.ts');
|
|
310
266
|
}
|
|
311
267
|
/**
|
|
312
268
|
* Register a callback when the value changes
|
|
313
|
-
* @param callback
|
|
269
|
+
* @param callback newValue and oldValue are references. You can use `a.draft` to make in-place mutations since `a.value` will not trigger `onChange` handers.
|
|
270
|
+
* @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.
|
|
314
271
|
*/
|
|
272
|
+
// todo 链式调用addOnChange改造
|
|
315
273
|
addOnChange(callback, key) {
|
|
316
274
|
if (typeof callback !== 'function') {
|
|
317
|
-
throw new Error('[@ktjs/core error]
|
|
275
|
+
throw new Error('[@ktjs/core error] KTRef.addOnChange: callback must be a function');
|
|
318
276
|
}
|
|
319
|
-
const k = key ?? IdGenerator.
|
|
320
|
-
this.
|
|
321
|
-
return
|
|
277
|
+
const k = key ?? IdGenerator.refOnChangeId;
|
|
278
|
+
this._changeHandlers.set(k, callback);
|
|
279
|
+
return this;
|
|
322
280
|
}
|
|
323
|
-
/**
|
|
324
|
-
* Unregister a callback
|
|
325
|
-
* @param key registered listener key
|
|
326
|
-
*/
|
|
327
281
|
removeOnChange(key) {
|
|
328
|
-
const callback = this.
|
|
329
|
-
this.
|
|
282
|
+
const callback = this._changeHandlers.get(key);
|
|
283
|
+
this._changeHandlers.delete(key);
|
|
330
284
|
return callback;
|
|
331
285
|
}
|
|
332
286
|
}
|
|
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
|
-
}
|
|
344
287
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
_value;
|
|
355
|
-
/**
|
|
356
|
-
* @internal
|
|
357
|
-
*/
|
|
358
|
-
_onChanges;
|
|
359
|
-
/**
|
|
360
|
-
* @internal
|
|
361
|
-
*/
|
|
362
|
-
_emit(newValue, oldValue, handlerKeys) {
|
|
363
|
-
if (handlerKeys) {
|
|
364
|
-
for (let i = 0; i < handlerKeys.length; i++) {
|
|
365
|
-
this._onChanges.get(handlerKeys[i])?.(newValue, oldValue);
|
|
366
|
-
}
|
|
288
|
+
// Use microqueue to schedule the flush of pending reactions
|
|
289
|
+
const reactiveToOldValue = new Map();
|
|
290
|
+
let scheduled = false;
|
|
291
|
+
const markMutation = (reactive) => {
|
|
292
|
+
if (!reactiveToOldValue.has(reactive)) {
|
|
293
|
+
// @ts-expect-error accessing protected property
|
|
294
|
+
reactiveToOldValue.set(reactive, reactive._value);
|
|
295
|
+
// # schedule by microqueue
|
|
296
|
+
if (scheduled) {
|
|
367
297
|
return;
|
|
368
298
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
299
|
+
scheduled = true;
|
|
300
|
+
Promise.resolve().then(() => {
|
|
301
|
+
scheduled = false;
|
|
302
|
+
reactiveToOldValue.forEach((oldValue, reactive) => {
|
|
303
|
+
// @ts-expect-error accessing protected property
|
|
304
|
+
reactive._changeHandlers.forEach((handler) => handler(reactive.value, oldValue));
|
|
305
|
+
});
|
|
306
|
+
reactiveToOldValue.clear();
|
|
307
|
+
});
|
|
377
308
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
class KTRef extends KTReactive {
|
|
312
|
+
ktType = 3 /* KTReactiveType.Ref */;
|
|
313
|
+
// ! Cannot be omitted, otherwise this will override `KTReactive` with only setter. And getter will return undefined.
|
|
381
314
|
get value() {
|
|
382
315
|
return this._value;
|
|
383
316
|
}
|
|
@@ -389,317 +322,29 @@ class KTRef {
|
|
|
389
322
|
this._value = newValue;
|
|
390
323
|
this._emit(newValue, oldValue);
|
|
391
324
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
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;
|
|
414
|
-
}
|
|
415
|
-
toComputed(calculator, dependencies) {
|
|
416
|
-
return computed(() => calculator(this.value), dependencies ? [this, ...dependencies] : [this]);
|
|
417
|
-
}
|
|
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
|
-
addOnChange(callback, key) {
|
|
424
|
-
if (typeof callback !== 'function') {
|
|
425
|
-
throw new Error('[@ktjs/core error] KTRef.addOnChange: callback must be a function');
|
|
426
|
-
}
|
|
427
|
-
const k = key ?? IdGenerator.refOnChangeId;
|
|
428
|
-
this._onChanges.set(k, callback);
|
|
429
|
-
return k;
|
|
430
|
-
}
|
|
431
|
-
removeOnChange(key) {
|
|
432
|
-
const callback = this._onChanges.get(key);
|
|
433
|
-
this._onChanges.delete(key);
|
|
434
|
-
return callback;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
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
|
-
};
|
|
453
|
-
|
|
454
|
-
class KTArrayRef extends KTRef {
|
|
455
|
-
constructor(value, onChange) {
|
|
456
|
-
super(value, onChange);
|
|
457
|
-
this.ktType = 3 /* 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;
|
|
325
|
+
// todo 编译器要对这个属性的逃逸(也就是什么都没改或者被赋值)进行检测,比如const a = xxx.draft.
|
|
326
|
+
get draft() {
|
|
327
|
+
markMutation(this);
|
|
328
|
+
return this._value;
|
|
493
329
|
}
|
|
494
330
|
/**
|
|
495
|
-
*
|
|
331
|
+
* Force all listeners to run even when reference identity has not changed.
|
|
496
332
|
*/
|
|
497
|
-
|
|
498
|
-
|
|
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);
|
|
511
|
-
|
|
512
|
-
class KTDateRef extends KTRef {
|
|
513
|
-
constructor(value, onChange) {
|
|
514
|
-
super(value, onChange);
|
|
515
|
-
this.ktType = 8 /* 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 = 4 /* 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]);
|
|
585
|
-
}
|
|
586
|
-
clear() {
|
|
587
|
-
return applyArgless(this, this._value.clear);
|
|
333
|
+
notify(oldValue = this._value, newValue = this._value, handlerKeys) {
|
|
334
|
+
return this._emit(newValue, oldValue, handlerKeys);
|
|
588
335
|
}
|
|
589
336
|
}
|
|
590
|
-
const mapRef = (value, onChange) => new KTMapRef(value, onChange);
|
|
591
|
-
|
|
592
|
-
class KTSetRef extends KTRef {
|
|
593
|
-
constructor(value, onChange) {
|
|
594
|
-
super(value, onChange);
|
|
595
|
-
this.ktType = 5 /* KTReactiveType.SetRef */;
|
|
596
|
-
}
|
|
597
|
-
get size() {
|
|
598
|
-
return this._value.size;
|
|
599
|
-
}
|
|
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);
|
|
615
|
-
|
|
616
|
-
class KTWeakMapRef extends KTRef {
|
|
617
|
-
constructor(value, onChange) {
|
|
618
|
-
super(value, onChange);
|
|
619
|
-
this.ktType = 6 /* 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]);
|
|
633
|
-
}
|
|
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 = 7 /* KTReactiveType.WeakSetRef */;
|
|
641
|
-
}
|
|
642
|
-
has(value) {
|
|
643
|
-
return this._value.has(value);
|
|
644
|
-
}
|
|
645
|
-
add(value) {
|
|
646
|
-
apply(this, this._value.add, [value]);
|
|
647
|
-
return this;
|
|
648
|
-
}
|
|
649
|
-
delete(value) {
|
|
650
|
-
return apply(this, this._value.delete, [value]);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
const weakSetRef = (value, onChange) => new KTWeakSetRef(value, onChange);
|
|
654
|
-
|
|
655
337
|
/**
|
|
656
|
-
*
|
|
657
|
-
* -
|
|
658
|
-
* -
|
|
659
|
-
*
|
|
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);
|
|
685
|
-
}
|
|
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.
|
|
338
|
+
* Create a `KTRef` object.
|
|
339
|
+
* - use `refObject.state` to get plain data
|
|
340
|
+
* - use `refObject.map(calculator)` to create a computed value based on this ref
|
|
341
|
+
* - use `refObject.mutable` to set too, but it will recalculate in the next microtask. Useful for deep objects, `Map`, `Set` or other custom objects
|
|
691
342
|
*
|
|
692
343
|
* @param value any data
|
|
693
344
|
* @param onChange event handler triggered when the value changes, with signature `(newValue, oldValue) => void`
|
|
694
345
|
* @returns
|
|
695
346
|
*/
|
|
696
|
-
const ref = (
|
|
697
|
-
ref.array = arrayRef;
|
|
698
|
-
ref.date = dateRef;
|
|
699
|
-
ref.map = mapRef;
|
|
700
|
-
ref.set = setRef;
|
|
701
|
-
ref.weakMap = weakMapRef;
|
|
702
|
-
ref.weakSet = weakSetRef;
|
|
347
|
+
const ref = (value) => new KTRef(value);
|
|
703
348
|
/**
|
|
704
349
|
* Assert k-model to be a ref object
|
|
705
350
|
*/
|
|
@@ -734,6 +379,67 @@ const $initRef = (props, node) => {
|
|
|
734
379
|
}
|
|
735
380
|
};
|
|
736
381
|
|
|
382
|
+
class KTComputed extends KTReactive {
|
|
383
|
+
ktType = 2 /* KTReactiveType.Computed */;
|
|
384
|
+
/**
|
|
385
|
+
* @internal
|
|
386
|
+
*/
|
|
387
|
+
_calculator;
|
|
388
|
+
/**
|
|
389
|
+
* @internal
|
|
390
|
+
*/
|
|
391
|
+
_recalculate(forceEmit = false, handlerKeys) {
|
|
392
|
+
const oldValue = this._value;
|
|
393
|
+
const newValue = this._calculator();
|
|
394
|
+
if (oldValue === newValue) {
|
|
395
|
+
if (forceEmit) {
|
|
396
|
+
this._emit(newValue, oldValue, handlerKeys);
|
|
397
|
+
}
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
400
|
+
this._value = newValue;
|
|
401
|
+
this._emit(newValue, oldValue, handlerKeys);
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
// todo 侦听的dependency数量比较多的,纳入scheduler
|
|
405
|
+
constructor(_calculator, dependencies) {
|
|
406
|
+
super(_calculator());
|
|
407
|
+
this._calculator = _calculator;
|
|
408
|
+
for (let i = 0; i < dependencies.length; i++) {
|
|
409
|
+
dependencies[i].addOnChange(() => this._recalculate());
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
414
|
+
*/
|
|
415
|
+
get value() {
|
|
416
|
+
return this._value;
|
|
417
|
+
}
|
|
418
|
+
set value(_newValue) {
|
|
419
|
+
console.warn('[@ktjs/core warn]',`'value' of Computed are read-only.`);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Force listeners to run once with the latest computed result.
|
|
423
|
+
*/
|
|
424
|
+
notify(handlerKeys) {
|
|
425
|
+
return this._recalculate(true, handlerKeys);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
KTReactive.prototype.map = function (calculator, dependencies) {
|
|
429
|
+
return new KTComputed(() => calculator(this._value), dependencies ? [this, ...dependencies] : [this]);
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* Create a reactive computed value
|
|
433
|
+
* @param computeFn
|
|
434
|
+
* @param dependencies refs and computeds that this computed depends on
|
|
435
|
+
*/
|
|
436
|
+
function computed(computeFn, dependencies) {
|
|
437
|
+
if (dependencies.some((v) => !isKT(v))) {
|
|
438
|
+
throw new Error('[@ktjs/core error] computed: all reactives must be KTRef or KTComputed instances');
|
|
439
|
+
}
|
|
440
|
+
return new KTComputed(computeFn, dependencies);
|
|
441
|
+
}
|
|
442
|
+
|
|
737
443
|
/**
|
|
738
444
|
* Register a reactive effect with options.
|
|
739
445
|
* @param effectFn The effect function to run when dependencies change
|
|
@@ -760,7 +466,8 @@ function effect(effectFn, reactives, options) {
|
|
|
760
466
|
};
|
|
761
467
|
// subscribe to dependencies
|
|
762
468
|
for (let i = 0; i < reactives.length; i++) {
|
|
763
|
-
listenerKeys[i] =
|
|
469
|
+
listenerKeys[i] = i;
|
|
470
|
+
reactives[i].addOnChange(run, i);
|
|
764
471
|
}
|
|
765
472
|
// auto run unless lazy
|
|
766
473
|
if (!lazy) {
|
|
@@ -780,17 +487,12 @@ function effect(effectFn, reactives, options) {
|
|
|
780
487
|
};
|
|
781
488
|
}
|
|
782
489
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
return ref(value, onChange);
|
|
792
|
-
}
|
|
793
|
-
};
|
|
490
|
+
/**
|
|
491
|
+
*
|
|
492
|
+
* @param value
|
|
493
|
+
* @returns
|
|
494
|
+
*/
|
|
495
|
+
const toReactive = (value) => isKT(value) ? value : ref(value);
|
|
794
496
|
/**
|
|
795
497
|
* Extracts the value from a KTReactive, or returns the value directly if it's not reactive.
|
|
796
498
|
*/
|
|
@@ -838,7 +540,7 @@ function applyKModel(element, valueRef) {
|
|
|
838
540
|
* ## About
|
|
839
541
|
* @package @ktjs/core
|
|
840
542
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
841
|
-
* @version 0.
|
|
543
|
+
* @version 0.33.0 (Last Update: 2026.03.21 22:19:51.700)
|
|
842
544
|
* @license MIT
|
|
843
545
|
* @link https://github.com/baendlorel/kt.js
|
|
844
546
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -963,7 +665,7 @@ function Fragment$1(props) {
|
|
|
963
665
|
observer = undefined;
|
|
964
666
|
anchor.__kt_fragment_list__ = elements;
|
|
965
667
|
};
|
|
966
|
-
const childrenRef = toReactive(props.children
|
|
668
|
+
const childrenRef = toReactive(props.children).addOnChange(redraw);
|
|
967
669
|
const renderInitial = () => {
|
|
968
670
|
const current = childrenRef.value;
|
|
969
671
|
elements.length = 0;
|
|
@@ -1026,7 +728,7 @@ function convertChildrenToElements(children) {
|
|
|
1026
728
|
processChild(child.value);
|
|
1027
729
|
return;
|
|
1028
730
|
}
|
|
1029
|
-
console.warn('Fragment: unsupported child type', child);
|
|
731
|
+
console.warn('[@ktjs/core warn]','Fragment: unsupported child type', child);
|
|
1030
732
|
};
|
|
1031
733
|
processChild(children);
|
|
1032
734
|
return elements;
|
|
@@ -1084,7 +786,7 @@ function KTAsync(props) {
|
|
|
1084
786
|
return comp;
|
|
1085
787
|
}
|
|
1086
788
|
|
|
1087
|
-
//
|
|
789
|
+
// task 对于template标签的for和if,会编译为fragment,可特殊处理,让它们保持原样
|
|
1088
790
|
/**
|
|
1089
791
|
* KTFor - List rendering component with key-based optimization
|
|
1090
792
|
* Returns a Comment anchor node with rendered elements in __kt_for_list__
|
|
@@ -1184,8 +886,7 @@ function KTFor(props) {
|
|
|
1184
886
|
}
|
|
1185
887
|
else {
|
|
1186
888
|
// Insert at end
|
|
1187
|
-
let
|
|
1188
|
-
let temp = nextSibling;
|
|
889
|
+
let temp = anchor.nextSibling; // ?? 这里难道不是null?
|
|
1189
890
|
while (temp && newElements.includes(temp)) {
|
|
1190
891
|
temp = temp.nextSibling;
|
|
1191
892
|
}
|
|
@@ -1221,7 +922,7 @@ function KTFor(props) {
|
|
|
1221
922
|
return anchor;
|
|
1222
923
|
};
|
|
1223
924
|
const { key: currentKey = (item) => item, map: currentMap = $identity } = props;
|
|
1224
|
-
const listRef = toReactive(props.list
|
|
925
|
+
const listRef = toReactive(props.list).addOnChange(redraw);
|
|
1225
926
|
const anchor = document.createComment('kt-for');
|
|
1226
927
|
// Map to track rendered nodes by key
|
|
1227
928
|
const nodeMap = new Map();
|
|
@@ -1306,5 +1007,5 @@ function KTConditional(condition, tagIf, propsIf, tagElse, propsElse) {
|
|
|
1306
1007
|
}
|
|
1307
1008
|
}
|
|
1308
1009
|
|
|
1309
|
-
export { $initRef, $modelOrRef, Fragment,
|
|
1010
|
+
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
1011
|
//# sourceMappingURL=index.mjs.map
|