@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/README.md +35 -3
- package/dist/index.d.ts +108 -318
- package/dist/index.mjs +301 -1129
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,40 +1,10 @@
|
|
|
1
|
-
import { $isArray, $isThenable, $isNode, $
|
|
1
|
+
import { $isArray, $isThenable, $isNode, $emptyFn, $is, $applyModel, $forEach, $identity } from "@ktjs/shared";
|
|
2
2
|
|
|
3
|
-
const isKT =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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) =>
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
element
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
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 =
|
|
61
|
+
const assureNode = o => $isNode(o) ? o : document.createTextNode(o);
|
|
62
|
+
|
|
155
63
|
function apdSingle(element, c) {
|
|
156
|
-
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
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
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
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.
|
|
109
|
+
return this._changeHandlers.forEach(c => c(newValue, oldValue)), this;
|
|
370
110
|
}
|
|
371
|
-
constructor(_value
|
|
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(
|
|
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
|
-
|
|
416
|
-
|
|
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
|
|
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.
|
|
429
|
-
return k;
|
|
127
|
+
return this._changeHandlers.set(k, callback), this;
|
|
430
128
|
}
|
|
431
129
|
removeOnChange(key) {
|
|
432
|
-
const callback = this.
|
|
433
|
-
this.
|
|
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
|
-
|
|
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
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
this.
|
|
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
|
-
|
|
587
|
-
|
|
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
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
-
|
|
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
|
-
|
|
643
|
-
return this._value
|
|
189
|
+
get value() {
|
|
190
|
+
return this._value;
|
|
644
191
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
return this;
|
|
192
|
+
set value(_newValue) {
|
|
193
|
+
console.warn("[@ktjs/core warn]", "'value' of Computed are read-only.");
|
|
648
194
|
}
|
|
649
|
-
|
|
650
|
-
return
|
|
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
|
-
|
|
657
|
-
|
|
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 =
|
|
746
|
-
|
|
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 (
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
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
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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
|
-
|
|
784
|
-
|
|
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
|
-
|
|
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
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (element.type
|
|
807
|
-
|
|
808
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
applyContent(element, content)
|
|
860
|
-
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
-
|
|
892
|
-
|
|
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
|
|
897
|
-
const result = originAppendChild.call(this, node);
|
|
898
|
-
|
|
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
|
|
906
|
-
const result = originInsertBefore.call(this, node, child);
|
|
907
|
-
|
|
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) =>
|
|
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
|
-
|
|
1047
|
-
const svg = (tag, props) => create(svg$1, tag, props);
|
|
1048
|
-
|
|
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
|
|
1055
|
-
if (!children)
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
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
|
-
|
|
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(
|
|
1078
|
-
|
|
1079
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1112
|
-
|
|
1113
|
-
if (
|
|
1114
|
-
|
|
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
|
-
|
|
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
|
|
1133
|
-
return anchor;
|
|
398
|
+
return parent.insertBefore(fragment, anchor.nextSibling), anchor.__kt_for_list__ = newElements,
|
|
399
|
+
anchor;
|
|
1134
400
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
466
|
+
return condition.addOnChange(newValue => {
|
|
1291
467
|
const old = current;
|
|
1292
|
-
current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse);
|
|
1293
|
-
|
|
1294
|
-
});
|
|
1295
|
-
return current;
|
|
468
|
+
current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse), old.replaceWith(current);
|
|
469
|
+
}), current;
|
|
1296
470
|
}
|
|
1297
|
-
|
|
1298
|
-
const dummy = placeholder(
|
|
471
|
+
{
|
|
472
|
+
const dummy = placeholder("kt-conditional");
|
|
1299
473
|
let current = condition.value ? jsxh(tagIf, propsIf) : dummy;
|
|
1300
|
-
condition.addOnChange(
|
|
474
|
+
return condition.addOnChange(newValue => {
|
|
1301
475
|
const old = current;
|
|
1302
|
-
current = newValue ? jsxh(tagIf, propsIf) : dummy;
|
|
1303
|
-
|
|
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,
|
|
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
|