@ktjs/core 0.33.0 → 0.33.2
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.d.ts +1 -6
- package/dist/index.mjs +282 -811
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,10 @@
|
|
|
1
|
-
import { $isArray, $isThenable, $isNode, $emptyFn, $is, $applyModel, $forEach, $identity } from
|
|
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 === 3 /* KTReactiveType.Ref */;
|
|
11
|
-
};
|
|
12
|
-
const isComputed = (obj) => obj?.ktType === 2 /* KTReactiveType.Computed */;
|
|
13
|
-
|
|
14
|
-
const booleanHandler = (element, key, value) => {
|
|
15
|
-
if (key in element) {
|
|
16
|
-
element[key] = !!value;
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
element.setAttribute(key, value);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
const valueHandler = (element, key, value) => {
|
|
23
|
-
if (key in element) {
|
|
24
|
-
element[key] = value;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
element.setAttribute(key, value);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
// Attribute handlers map for optimized lookup
|
|
31
|
-
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 = {
|
|
32
8
|
checked: booleanHandler,
|
|
33
9
|
selected: booleanHandler,
|
|
34
10
|
value: valueHandler,
|
|
@@ -49,485 +25,224 @@ const handlers = {
|
|
|
49
25
|
muted: booleanHandler,
|
|
50
26
|
defer: booleanHandler,
|
|
51
27
|
async: booleanHandler,
|
|
52
|
-
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;
|
|
53
31
|
};
|
|
54
32
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
element
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (isKT(classValue)) {
|
|
69
|
-
element.setAttribute('class', classValue.value);
|
|
70
|
-
classValue.addOnChange((v) => element.setAttribute('class', v));
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
element.setAttribute('class', classValue);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const style = attr.style;
|
|
77
|
-
if (style) {
|
|
78
|
-
if (typeof style === 'string') {
|
|
79
|
-
element.setAttribute('style', style);
|
|
80
|
-
}
|
|
81
|
-
else if (typeof style === 'object') {
|
|
82
|
-
if (isKT(style)) {
|
|
83
|
-
setElementStyle(element, style.value);
|
|
84
|
-
style.addOnChange((v) => setElementStyle(element, v));
|
|
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;
|
|
85
46
|
}
|
|
86
|
-
|
|
87
|
-
|
|
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);
|
|
88
56
|
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if ('k-html' in attr) {
|
|
92
|
-
const html = attr['k-html'];
|
|
93
|
-
if (isKT(html)) {
|
|
94
|
-
element.innerHTML = html.value;
|
|
95
|
-
html.addOnChange((v) => (element.innerHTML = v));
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
element.innerHTML = html;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
for (const key in attr) {
|
|
102
|
-
// & Arranged in order of usage frequency
|
|
103
|
-
if (
|
|
104
|
-
// key === 'k-if' ||
|
|
105
|
-
// key === 'k-else' ||
|
|
106
|
-
key === 'k-model' ||
|
|
107
|
-
key === 'k-for' ||
|
|
108
|
-
key === 'k-key' ||
|
|
109
|
-
key === 'ref' ||
|
|
110
|
-
key === 'class' ||
|
|
111
|
-
key === 'className' ||
|
|
112
|
-
key === 'style' ||
|
|
113
|
-
key === 'children' ||
|
|
114
|
-
key === 'k-html') {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
const o = attr[key];
|
|
118
|
-
// normal event handler
|
|
119
|
-
if (key.startsWith('on:')) {
|
|
120
|
-
if (o) {
|
|
121
|
-
element.addEventListener(key.slice(3), o); // chop off the `on:`
|
|
122
|
-
}
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
// normal attributes
|
|
126
|
-
const handler = handlers[key] || defaultHandler;
|
|
127
|
-
if (isKT(o)) {
|
|
128
|
-
handler(element, key, o.value);
|
|
129
|
-
o.addOnChange((v) => handler(element, key, v));
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
handler(element, key, o);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
function applyAttr(element, attr) {
|
|
137
|
-
if (!attr) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
if (typeof attr === 'object' && attr !== null) {
|
|
141
|
-
attrIsObject(element, attr);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
throw new Error('[@ktjs/core error] attr must be an object.');
|
|
57
|
+
}(element, attr);
|
|
145
58
|
}
|
|
146
59
|
}
|
|
147
60
|
|
|
148
|
-
const assureNode =
|
|
61
|
+
const assureNode = o => $isNode(o) ? o : document.createTextNode(o);
|
|
62
|
+
|
|
149
63
|
function apdSingle(element, c) {
|
|
150
|
-
|
|
151
|
-
if (c === undefined || c === null || c === false) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
if (isKT(c)) {
|
|
64
|
+
if (null != c && !1 !== c) if (isKT(c)) {
|
|
155
65
|
let node = assureNode(c.value);
|
|
156
|
-
element.appendChild(node)
|
|
157
|
-
c.addOnChange((newValue, _oldValue) => {
|
|
66
|
+
element.appendChild(node), c.addOnChange((newValue, _oldValue) => {
|
|
158
67
|
const oldNode = node;
|
|
159
|
-
node = assureNode(newValue);
|
|
160
|
-
oldNode.replaceWith(node);
|
|
68
|
+
node = assureNode(newValue), oldNode.replaceWith(node);
|
|
161
69
|
});
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
70
|
+
} else {
|
|
164
71
|
const node = assureNode(c);
|
|
165
72
|
element.appendChild(node);
|
|
166
|
-
// Handle KTFor anchor
|
|
167
73
|
const list = node.__kt_for_list__;
|
|
168
|
-
|
|
169
|
-
apd(element, list);
|
|
170
|
-
}
|
|
74
|
+
$isArray(list) && apd(element, list);
|
|
171
75
|
}
|
|
172
76
|
}
|
|
77
|
+
|
|
173
78
|
function apd(element, c) {
|
|
174
|
-
if ($isThenable(c)) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if ($isThenable(ci)) {
|
|
182
|
-
const comment = document.createComment('ktjs-promise-placeholder');
|
|
183
|
-
element.appendChild(comment);
|
|
184
|
-
ci.then((awaited) => comment.replaceWith(awaited));
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
apdSingle(element, ci);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// & here is thened, so must be a simple elementj
|
|
193
|
-
apdSingle(element, c);
|
|
194
|
-
}
|
|
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);
|
|
195
86
|
}
|
|
87
|
+
|
|
196
88
|
function applyContent(element, content) {
|
|
197
|
-
if ($isArray(content))
|
|
198
|
-
for (let i = 0; i < content.length; i++) {
|
|
199
|
-
apd(element, content[i]);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
apd(element, content);
|
|
204
|
-
}
|
|
89
|
+
if ($isArray(content)) for (let i = 0; i < content.length; i++) apd(element, content[i]); else apd(element, content);
|
|
205
90
|
}
|
|
206
91
|
|
|
207
|
-
// # internal methods that cannot be placed in @ktjs/shared
|
|
208
92
|
const IdGenerator = {
|
|
209
93
|
_refOnChangeId: 1,
|
|
210
94
|
get refOnChangeId() {
|
|
211
95
|
return this._refOnChangeId++;
|
|
212
|
-
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
213
98
|
|
|
214
99
|
class KTReactive {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
*/
|
|
218
|
-
isKT = true;
|
|
219
|
-
ktType = 1 /* KTReactiveType.Reative */;
|
|
220
|
-
/**
|
|
221
|
-
* @internal
|
|
222
|
-
*/
|
|
100
|
+
isKT=!0;
|
|
101
|
+
ktType=1;
|
|
223
102
|
_value;
|
|
224
|
-
|
|
225
|
-
* @internal
|
|
226
|
-
*/
|
|
227
|
-
_changeHandlers = new Map();
|
|
228
|
-
/**
|
|
229
|
-
* @internal
|
|
230
|
-
*/
|
|
103
|
+
_changeHandlers=new Map;
|
|
231
104
|
_emit(newValue, oldValue, handlerKeys) {
|
|
232
105
|
if (handlerKeys) {
|
|
233
|
-
for (let i = 0; i < handlerKeys.length; i++)
|
|
234
|
-
this._changeHandlers.get(handlerKeys[i])?.(newValue, oldValue);
|
|
235
|
-
}
|
|
106
|
+
for (let i = 0; i < handlerKeys.length; i++) this._changeHandlers.get(handlerKeys[i])?.(newValue, oldValue);
|
|
236
107
|
return this;
|
|
237
108
|
}
|
|
238
|
-
this._changeHandlers.forEach(
|
|
239
|
-
return this;
|
|
109
|
+
return this._changeHandlers.forEach(c => c(newValue, oldValue)), this;
|
|
240
110
|
}
|
|
241
111
|
constructor(_value) {
|
|
242
|
-
this._value = _value;
|
|
243
|
-
this._changeHandlers = new Map();
|
|
112
|
+
this._value = _value, this._changeHandlers = new Map;
|
|
244
113
|
}
|
|
245
|
-
/**
|
|
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
|
|
249
|
-
*/
|
|
250
114
|
get value() {
|
|
251
115
|
return this._value;
|
|
252
116
|
}
|
|
253
|
-
set value(_newValue) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
/**
|
|
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`
|
|
260
|
-
*/
|
|
261
|
-
notify(..._args) {
|
|
262
|
-
throw new Error('This is meant to be override in ref.ts and computed.ts');
|
|
117
|
+
set value(_newValue) {}
|
|
118
|
+
notify(handlerKeys) {
|
|
119
|
+
return this._emit(this._value, this._value, handlerKeys);
|
|
263
120
|
}
|
|
264
121
|
map(..._args) {
|
|
265
|
-
throw new Error(
|
|
122
|
+
throw new Error("This is meant to be override in computed.ts");
|
|
266
123
|
}
|
|
267
|
-
/**
|
|
268
|
-
* Register a callback when the value changes
|
|
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.
|
|
271
|
-
*/
|
|
272
|
-
// todo 链式调用addOnChange改造
|
|
273
124
|
addOnChange(callback, key) {
|
|
274
|
-
if (typeof callback
|
|
275
|
-
throw new Error('[@ktjs/core error] KTRef.addOnChange: callback must be a function');
|
|
276
|
-
}
|
|
125
|
+
if ("function" != typeof callback) throw new Error("[@ktjs/core error] KTRef.addOnChange: callback must be a function");
|
|
277
126
|
const k = key ?? IdGenerator.refOnChangeId;
|
|
278
|
-
this._changeHandlers.set(k, callback);
|
|
279
|
-
return this;
|
|
127
|
+
return this._changeHandlers.set(k, callback), this;
|
|
280
128
|
}
|
|
281
129
|
removeOnChange(key) {
|
|
282
130
|
const callback = this._changeHandlers.get(key);
|
|
283
|
-
this._changeHandlers.delete(key);
|
|
284
|
-
return callback;
|
|
131
|
+
return this._changeHandlers.delete(key), callback;
|
|
285
132
|
}
|
|
286
133
|
}
|
|
287
134
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
let scheduled =
|
|
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) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
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
|
-
});
|
|
308
|
-
}
|
|
309
|
-
};
|
|
135
|
+
const reactiveToOldValue = new Map;
|
|
136
|
+
|
|
137
|
+
let scheduled = !1;
|
|
310
138
|
|
|
311
139
|
class KTRef extends KTReactive {
|
|
312
|
-
ktType
|
|
313
|
-
// ! Cannot be omitted, otherwise this will override `KTReactive` with only setter. And getter will return undefined.
|
|
140
|
+
ktType=3;
|
|
314
141
|
get value() {
|
|
315
142
|
return this._value;
|
|
316
143
|
}
|
|
317
144
|
set value(newValue) {
|
|
318
|
-
if ($is(newValue, this._value))
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
145
|
+
if ($is(newValue, this._value)) return;
|
|
321
146
|
const oldValue = this._value;
|
|
322
|
-
this._value = newValue;
|
|
323
|
-
this._emit(newValue, oldValue);
|
|
147
|
+
this._value = newValue, this._emit(newValue, oldValue);
|
|
324
148
|
}
|
|
325
|
-
// todo 编译器要对这个属性的逃逸(也就是什么都没改或者被赋值)进行检测,比如const a = xxx.draft.
|
|
326
149
|
get draft() {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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;
|
|
335
160
|
}
|
|
336
161
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
* @param value any data
|
|
344
|
-
* @param onChange event handler triggered when the value changes, with signature `(newValue, oldValue) => void`
|
|
345
|
-
* @returns
|
|
346
|
-
*/
|
|
347
|
-
const ref = (value) => new KTRef(value);
|
|
348
|
-
/**
|
|
349
|
-
* Assert k-model to be a ref object
|
|
350
|
-
*/
|
|
351
|
-
const $modelOrRef = (props, defaultValue) => {
|
|
352
|
-
// & props is an object. Won't use it in any other place
|
|
353
|
-
if ('k-model' in props) {
|
|
354
|
-
const kmodel = props['k-model'];
|
|
355
|
-
if (isRef(kmodel)) {
|
|
356
|
-
return kmodel;
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
throw new Error(`[@ktjs/core error] k-model data must be a KTRef object, please use 'ref(...)' to wrap it.`);
|
|
360
|
-
}
|
|
162
|
+
|
|
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.");
|
|
361
168
|
}
|
|
362
169
|
return ref(defaultValue);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Whether `props.ref` is a `KTRef` only needs to be checked in the initial render
|
|
367
|
-
*/
|
|
368
|
-
const $initRef = (props, node) => {
|
|
369
|
-
if (!('ref' in props)) {
|
|
370
|
-
return $emptyFn;
|
|
371
|
-
}
|
|
170
|
+
}, $refSetter = (props, node) => props.ref.value = node, $initRef = (props, node) => {
|
|
171
|
+
if (!("ref" in props)) return $emptyFn;
|
|
372
172
|
const r = props.ref;
|
|
373
|
-
if (isRef(r))
|
|
374
|
-
|
|
375
|
-
return $refSetter;
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
throw new Error('[@ktjs/core error] Fragment: ref must be a KTRef');
|
|
379
|
-
}
|
|
173
|
+
if (isRef(r)) return r.value = node, $refSetter;
|
|
174
|
+
throw new Error("[@ktjs/core error] Fragment: ref must be a KTRef");
|
|
380
175
|
};
|
|
381
176
|
|
|
382
177
|
class KTComputed extends KTReactive {
|
|
383
|
-
ktType
|
|
384
|
-
/**
|
|
385
|
-
* @internal
|
|
386
|
-
*/
|
|
178
|
+
ktType=2;
|
|
387
179
|
_calculator;
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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;
|
|
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);
|
|
403
184
|
}
|
|
404
|
-
// todo 侦听的dependency数量比较多的,纳入scheduler
|
|
405
185
|
constructor(_calculator, dependencies) {
|
|
406
|
-
super(_calculator());
|
|
407
|
-
|
|
408
|
-
for (let i = 0; i < dependencies.length; i++) {
|
|
409
|
-
dependencies[i].addOnChange(() => this._recalculate());
|
|
410
|
-
}
|
|
186
|
+
super(_calculator()), this._calculator = _calculator;
|
|
187
|
+
for (let i = 0; i < dependencies.length; i++) dependencies[i].addOnChange(() => this._recalculate());
|
|
411
188
|
}
|
|
412
|
-
/**
|
|
413
|
-
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
414
|
-
*/
|
|
415
189
|
get value() {
|
|
416
190
|
return this._value;
|
|
417
191
|
}
|
|
418
192
|
set value(_newValue) {
|
|
419
|
-
console.warn(
|
|
193
|
+
console.warn("[@ktjs/core warn]", "'value' of Computed are read-only.");
|
|
420
194
|
}
|
|
421
|
-
/**
|
|
422
|
-
* Force listeners to run once with the latest computed result.
|
|
423
|
-
*/
|
|
424
195
|
notify(handlerKeys) {
|
|
425
|
-
return this._recalculate(
|
|
196
|
+
return this._recalculate(!0, handlerKeys);
|
|
426
197
|
}
|
|
427
198
|
}
|
|
428
|
-
|
|
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
|
-
*/
|
|
199
|
+
|
|
436
200
|
function computed(computeFn, dependencies) {
|
|
437
|
-
if (dependencies.some(
|
|
438
|
-
throw new Error('[@ktjs/core error] computed: all reactives must be KTRef or KTComputed instances');
|
|
439
|
-
}
|
|
201
|
+
if (dependencies.some(v => !isKT(v))) throw new Error("[@ktjs/core error] computed: all reactives must be KTRef or KTComputed instances");
|
|
440
202
|
return new KTComputed(computeFn, dependencies);
|
|
441
203
|
}
|
|
442
204
|
|
|
443
|
-
/**
|
|
444
|
-
* Register a reactive effect with options.
|
|
445
|
-
* @param effectFn The effect function to run when dependencies change
|
|
446
|
-
* @param reactives The reactive dependencies
|
|
447
|
-
* @param options Effect options: lazy, onCleanup, debugName
|
|
448
|
-
* @returns stop function to remove all listeners
|
|
449
|
-
*/
|
|
450
205
|
function effect(effectFn, reactives, options) {
|
|
451
|
-
const { lazy =
|
|
452
|
-
|
|
453
|
-
let active = true;
|
|
206
|
+
const {lazy: lazy = !1, onCleanup: onCleanup = $emptyFn, debugName: debugName = ""} = Object(options), listenerKeys = [];
|
|
207
|
+
let active = !0;
|
|
454
208
|
const run = () => {
|
|
455
|
-
if (
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
463
|
-
catch (err) {
|
|
464
|
-
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
|
+
}
|
|
465
216
|
}
|
|
466
217
|
};
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (!lazy) {
|
|
474
|
-
run();
|
|
475
|
-
}
|
|
476
|
-
// stop function
|
|
477
|
-
return () => {
|
|
478
|
-
if (!active) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
active = false;
|
|
482
|
-
for (let i = 0; i < reactives.length; i++) {
|
|
483
|
-
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();
|
|
484
224
|
}
|
|
485
|
-
// final cleanup
|
|
486
|
-
onCleanup();
|
|
487
225
|
};
|
|
488
226
|
}
|
|
489
227
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* Extracts the value from a KTReactive, or returns the value directly if it's not reactive.
|
|
498
|
-
*/
|
|
228
|
+
KTReactive.prototype.map = function(calculator, dependencies) {
|
|
229
|
+
return new KTComputed(() => calculator(this._value), dependencies ? [ this, ...dependencies ] : [ this ]);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const toReactive = value => isKT(value) ? value : ref(value);
|
|
233
|
+
|
|
499
234
|
function dereactive(value) {
|
|
500
235
|
return isKT(value) ? value.value : value;
|
|
501
236
|
}
|
|
502
237
|
|
|
503
238
|
function applyKModel(element, valueRef) {
|
|
504
|
-
if (!isKT(valueRef))
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
if (element.type
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
if (element.type === 'number') {
|
|
513
|
-
$applyModel(element, valueRef, 'checked', 'change', Number);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
if (element.type === 'date') {
|
|
517
|
-
$applyModel(element, valueRef, 'checked', 'change', (v) => new Date(v));
|
|
518
|
-
return;
|
|
519
|
-
}
|
|
520
|
-
$applyModel(element, valueRef, 'value', 'input');
|
|
521
|
-
}
|
|
522
|
-
else if (element.tagName === 'SELECT') {
|
|
523
|
-
$applyModel(element, valueRef, 'value', 'change');
|
|
524
|
-
}
|
|
525
|
-
else if (element.tagName === 'TEXTAREA') {
|
|
526
|
-
$applyModel(element, valueRef, 'value', 'input');
|
|
527
|
-
}
|
|
528
|
-
else {
|
|
529
|
-
console.warn('[@ktjs/core warn]','not supported element for k-model:');
|
|
530
|
-
}
|
|
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:");
|
|
531
246
|
}
|
|
532
247
|
|
|
533
248
|
/**
|
|
@@ -540,470 +255,226 @@ function applyKModel(element, valueRef) {
|
|
|
540
255
|
* ## About
|
|
541
256
|
* @package @ktjs/core
|
|
542
257
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
543
|
-
* @version 0.33.
|
|
258
|
+
* @version 0.33.2 (Last Update: 2026.03.22 00:10:18.944)
|
|
544
259
|
* @license MIT
|
|
545
260
|
* @link https://github.com/baendlorel/kt.js
|
|
546
261
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
547
262
|
* @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
|
|
548
263
|
* @copyright Copyright (c) 2026 Kasukabe Tsumugi. All rights reserved.
|
|
549
|
-
*/
|
|
550
|
-
|
|
551
|
-
if (typeof tag !== 'string') {
|
|
552
|
-
throw new Error('[@ktjs/core error] tagName must be a string.');
|
|
553
|
-
}
|
|
554
|
-
// * 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.");
|
|
555
266
|
const element = document.createElement(tag);
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
applyContent(element, content)
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
// * start creating the element
|
|
569
|
-
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
570
|
-
// * Handle content
|
|
571
|
-
applyAttr(element, attr);
|
|
572
|
-
applyContent(element, content);
|
|
573
|
-
if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
|
|
574
|
-
applyKModel(element, attr['k-model']);
|
|
575
|
-
}
|
|
576
|
-
return element;
|
|
577
|
-
};
|
|
578
|
-
const mathml$1 = (tag, attr, content) => {
|
|
579
|
-
if (typeof tag !== 'string') {
|
|
580
|
-
throw new Error('[@ktjs/core error] tagName must be a string.');
|
|
581
|
-
}
|
|
582
|
-
// * start creating the element
|
|
583
|
-
const element = document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
|
|
584
|
-
// * Handle content
|
|
585
|
-
applyAttr(element, attr);
|
|
586
|
-
applyContent(element, content);
|
|
587
|
-
if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
|
|
588
|
-
applyKModel(element, attr['k-model']);
|
|
589
|
-
}
|
|
590
|
-
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;
|
|
591
279
|
};
|
|
592
280
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (typeof Node !== 'undefined' && !globalThis[FRAGMENT_MOUNT_PATCHED]) {
|
|
596
|
-
globalThis[FRAGMENT_MOUNT_PATCHED] = true;
|
|
281
|
+
if ("undefined" != typeof Node && !globalThis.__kt_fragment_mount_patched__) {
|
|
282
|
+
globalThis.__kt_fragment_mount_patched__ = !0;
|
|
597
283
|
const originAppendChild = Node.prototype.appendChild;
|
|
598
|
-
Node.prototype.appendChild = function
|
|
599
|
-
const result = originAppendChild.call(this, node);
|
|
600
|
-
|
|
601
|
-
if (typeof mount === 'function') {
|
|
602
|
-
mount();
|
|
603
|
-
}
|
|
604
|
-
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;
|
|
605
287
|
};
|
|
606
288
|
const originInsertBefore = Node.prototype.insertBefore;
|
|
607
|
-
Node.prototype.insertBefore = function
|
|
608
|
-
const result = originInsertBefore.call(this, node, child);
|
|
609
|
-
|
|
610
|
-
if (typeof mount === 'function') {
|
|
611
|
-
mount();
|
|
612
|
-
}
|
|
613
|
-
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;
|
|
614
292
|
};
|
|
615
293
|
}
|
|
616
|
-
/**
|
|
617
|
-
* Fragment - Container component for managing arrays of child elements
|
|
618
|
-
*
|
|
619
|
-
* Features:
|
|
620
|
-
* 1. Returns a comment anchor node, child elements are inserted after the anchor
|
|
621
|
-
* 2. Supports reactive arrays, automatically updates DOM when array changes
|
|
622
|
-
* 3. Basic version uses simple replacement algorithm (remove all old elements, insert all new elements)
|
|
623
|
-
* 4. Future enhancement: key-based optimization
|
|
624
|
-
*
|
|
625
|
-
* Usage example:
|
|
626
|
-
* ```tsx
|
|
627
|
-
* const children = ref([<div>A</div>, <div>B</div>]);
|
|
628
|
-
* const fragment = <Fragment children={children} />;
|
|
629
|
-
* document.body.appendChild(fragment);
|
|
630
|
-
*
|
|
631
|
-
* // Automatic update
|
|
632
|
-
* children.value = [<div>C</div>, <div>D</div>];
|
|
633
|
-
* ```
|
|
634
|
-
*/
|
|
635
|
-
function Fragment$1(props) {
|
|
636
|
-
const elements = [];
|
|
637
|
-
const anchor = document.createComment('kt-fragment');
|
|
638
|
-
let inserted = false;
|
|
639
|
-
let observer;
|
|
640
|
-
const redraw = () => {
|
|
641
|
-
const newElements = childrenRef.value;
|
|
642
|
-
const parent = anchor.parentNode;
|
|
643
|
-
if (!parent) {
|
|
644
|
-
elements.length = 0;
|
|
645
|
-
for (let i = 0; i < newElements.length; i++) {
|
|
646
|
-
elements.push(newElements[i]);
|
|
647
|
-
}
|
|
648
|
-
anchor.__kt_fragment_list__ = elements;
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
for (let i = 0; i < elements.length; i++) {
|
|
652
|
-
elements[i].remove();
|
|
653
|
-
}
|
|
654
|
-
const fragment = document.createDocumentFragment();
|
|
655
|
-
elements.length = 0;
|
|
656
|
-
for (let i = 0; i < newElements.length; i++) {
|
|
657
|
-
const element = newElements[i];
|
|
658
|
-
elements.push(element);
|
|
659
|
-
fragment.appendChild(element);
|
|
660
|
-
}
|
|
661
|
-
parent.insertBefore(fragment, anchor.nextSibling);
|
|
662
|
-
inserted = true;
|
|
663
|
-
delete anchor[FRAGMENT_MOUNT];
|
|
664
|
-
observer?.disconnect();
|
|
665
|
-
observer = undefined;
|
|
666
|
-
anchor.__kt_fragment_list__ = elements;
|
|
667
|
-
};
|
|
668
|
-
const childrenRef = toReactive(props.children).addOnChange(redraw);
|
|
669
|
-
const renderInitial = () => {
|
|
670
|
-
const current = childrenRef.value;
|
|
671
|
-
elements.length = 0;
|
|
672
|
-
const fragment = document.createDocumentFragment();
|
|
673
|
-
for (let i = 0; i < current.length; i++) {
|
|
674
|
-
const element = current[i];
|
|
675
|
-
elements.push(element);
|
|
676
|
-
fragment.appendChild(element);
|
|
677
|
-
}
|
|
678
|
-
anchor.__kt_fragment_list__ = elements;
|
|
679
|
-
const parent = anchor.parentNode;
|
|
680
|
-
if (parent && !inserted) {
|
|
681
|
-
parent.insertBefore(fragment, anchor.nextSibling);
|
|
682
|
-
inserted = true;
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
renderInitial();
|
|
686
|
-
anchor[FRAGMENT_MOUNT] = () => {
|
|
687
|
-
if (!inserted && anchor.parentNode) {
|
|
688
|
-
redraw();
|
|
689
|
-
}
|
|
690
|
-
};
|
|
691
|
-
observer = new MutationObserver(() => {
|
|
692
|
-
if (anchor.parentNode && !inserted) {
|
|
693
|
-
redraw();
|
|
694
|
-
observer?.disconnect();
|
|
695
|
-
observer = undefined;
|
|
696
|
-
}
|
|
697
|
-
});
|
|
698
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
699
|
-
$initRef(props, anchor);
|
|
700
|
-
return anchor;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Convert KTRawContent to HTMLElement array
|
|
704
|
-
*/
|
|
705
|
-
function convertChildrenToElements(children) {
|
|
706
|
-
const elements = [];
|
|
707
|
-
const processChild = (child) => {
|
|
708
|
-
if (child === undefined || child === null || child === false || child === true) {
|
|
709
|
-
// Ignore null, undefined, false, true
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
if ($isArray(child)) {
|
|
713
|
-
// Recursively process array
|
|
714
|
-
$forEach(child, processChild);
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
if (typeof child === 'string' || typeof child === 'number') {
|
|
718
|
-
const span = document.createElement('span');
|
|
719
|
-
span.textContent = String(child);
|
|
720
|
-
elements.push(span);
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
if (child instanceof HTMLElement) {
|
|
724
|
-
elements.push(child);
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
if (isKT(child)) {
|
|
728
|
-
processChild(child.value);
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
console.warn('[@ktjs/core warn]','Fragment: unsupported child type', child);
|
|
732
|
-
};
|
|
733
|
-
processChild(children);
|
|
734
|
-
return elements;
|
|
735
|
-
}
|
|
736
294
|
|
|
737
|
-
const jsxh = (tag, props) =>
|
|
738
|
-
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);
|
|
739
296
|
|
|
740
297
|
function create(creator, tag, props) {
|
|
741
|
-
if (props.ref && isComputed(props.ref))
|
|
742
|
-
throw new Error('[@ktjs/core error] Cannot assign a computed value to an element.');
|
|
743
|
-
}
|
|
298
|
+
if (props.ref && isComputed(props.ref)) throw new Error("[@ktjs/core error] Cannot assign a computed value to an element.");
|
|
744
299
|
const el = creator(tag, props, props.children);
|
|
745
|
-
$initRef(props, el);
|
|
746
|
-
return el;
|
|
300
|
+
return $initRef(props, el), el;
|
|
747
301
|
}
|
|
748
|
-
|
|
749
|
-
const svg = (tag, props) => create(svg$1, tag, props);
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Fragment support - returns an array of children
|
|
753
|
-
* Enhanced Fragment component that manages arrays of elements
|
|
754
|
-
*/
|
|
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
|
+
|
|
755
305
|
function Fragment(props) {
|
|
756
|
-
const { children
|
|
757
|
-
if (!children)
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
+
});
|
|
762
366
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
*/
|
|
766
|
-
const jsxDEV = (...args) => {
|
|
767
|
-
// console.log('JSX DEV called:', ...args);
|
|
768
|
-
// console.log('children', (args[1] as any)?.children);
|
|
769
|
-
return jsx(...args);
|
|
770
|
-
};
|
|
771
|
-
/**
|
|
772
|
-
* JSX runtime for React 17+ automatic runtime
|
|
773
|
-
* This is called when using jsx: "react-jsx" or "react-jsxdev"
|
|
774
|
-
*/
|
|
775
|
-
const jsxs = jsx;
|
|
367
|
+
|
|
368
|
+
const jsxDEV = (...args) => jsx(...args), jsxs = jsx;
|
|
776
369
|
|
|
777
370
|
function KTAsync(props) {
|
|
778
371
|
const raw = props.component(props);
|
|
779
|
-
let comp = props.skeleton ?? document.createComment(
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
}
|
|
783
|
-
else {
|
|
784
|
-
comp = raw;
|
|
785
|
-
}
|
|
786
|
-
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;
|
|
787
375
|
}
|
|
788
376
|
|
|
789
|
-
// task 对于template标签的for和if,会编译为fragment,可特殊处理,让它们保持原样
|
|
790
|
-
/**
|
|
791
|
-
* KTFor - List rendering component with key-based optimization
|
|
792
|
-
* Returns a Comment anchor node with rendered elements in __kt_for_list__
|
|
793
|
-
*/
|
|
794
377
|
function KTFor(props) {
|
|
795
|
-
const
|
|
796
|
-
const newList = listRef.value;
|
|
797
|
-
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;
|
|
798
380
|
if (!parent) {
|
|
799
|
-
// If not in DOM yet, just rebuild the list
|
|
800
381
|
const newElements = [];
|
|
801
382
|
nodeMap.clear();
|
|
802
383
|
for (let index = 0; index < newList.length; index++) {
|
|
803
|
-
const item = newList[index];
|
|
804
|
-
|
|
805
|
-
const node = currentMap(item, index, newList);
|
|
806
|
-
nodeMap.set(itemKey, node);
|
|
807
|
-
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);
|
|
808
386
|
}
|
|
809
|
-
anchor.__kt_for_list__ = newElements;
|
|
810
|
-
return anchor;
|
|
811
|
-
}
|
|
812
|
-
const oldLength = anchor.__kt_for_list__.length;
|
|
813
|
-
const newLength = newList.length;
|
|
814
|
-
// Fast path: empty list
|
|
815
|
-
if (newLength === 0) {
|
|
816
|
-
nodeMap.forEach((node) => node.remove());
|
|
817
|
-
nodeMap.clear();
|
|
818
|
-
anchor.__kt_for_list__ = [];
|
|
819
|
-
return anchor;
|
|
387
|
+
return anchor.__kt_for_list__ = newElements, anchor;
|
|
820
388
|
}
|
|
821
|
-
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
|
|
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();
|
|
825
394
|
for (let i = 0; i < newLength; i++) {
|
|
826
|
-
const item = newList[i];
|
|
827
|
-
|
|
828
|
-
const node = currentMap(item, i, newList);
|
|
829
|
-
nodeMap.set(itemKey, node);
|
|
830
|
-
newElements.push(node);
|
|
831
|
-
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);
|
|
832
397
|
}
|
|
833
|
-
parent.insertBefore(fragment, anchor.nextSibling)
|
|
834
|
-
anchor
|
|
835
|
-
return anchor;
|
|
398
|
+
return parent.insertBefore(fragment, anchor.nextSibling), anchor.__kt_for_list__ = newElements,
|
|
399
|
+
anchor;
|
|
836
400
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const newElements = new Array(newLength);
|
|
840
|
-
let maxNewIndexSoFar = 0;
|
|
841
|
-
let moved = false;
|
|
401
|
+
const newKeyToNewIndex = new Map, newElements = new Array(newLength);
|
|
402
|
+
let maxNewIndexSoFar = 0, moved = !1;
|
|
842
403
|
for (let i = 0; i < newLength; i++) {
|
|
843
|
-
const item = newList[i];
|
|
844
|
-
|
|
845
|
-
newKeyToNewIndex.set(itemKey, i);
|
|
846
|
-
if (nodeMap.has(itemKey)) {
|
|
847
|
-
// Reuse existing node
|
|
404
|
+
const item = newList[i], itemKey = currentKey(item, i, newList);
|
|
405
|
+
if (newKeyToNewIndex.set(itemKey, i), nodeMap.has(itemKey)) {
|
|
848
406
|
const node = nodeMap.get(itemKey);
|
|
849
|
-
newElements[i] = node;
|
|
850
|
-
|
|
851
|
-
if (i < maxNewIndexSoFar) {
|
|
852
|
-
moved = true;
|
|
853
|
-
}
|
|
854
|
-
else {
|
|
855
|
-
maxNewIndexSoFar = i;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
else {
|
|
859
|
-
// Create new node
|
|
860
|
-
newElements[i] = currentMap(item, i, newList);
|
|
861
|
-
}
|
|
407
|
+
newElements[i] = node, i < maxNewIndexSoFar ? moved = !0 : maxNewIndexSoFar = i;
|
|
408
|
+
} else newElements[i] = currentMap(item, i, newList);
|
|
862
409
|
}
|
|
863
|
-
// Remove nodes not in new list
|
|
864
410
|
const toRemove = [];
|
|
865
411
|
nodeMap.forEach((node, key) => {
|
|
866
|
-
|
|
867
|
-
toRemove.push(node);
|
|
868
|
-
}
|
|
412
|
+
newKeyToNewIndex.has(key) || toRemove.push(node);
|
|
869
413
|
});
|
|
870
|
-
for (let i = 0; i < toRemove.length; i++)
|
|
871
|
-
toRemove[i].remove();
|
|
872
|
-
}
|
|
873
|
-
// Update DOM with minimal operations
|
|
414
|
+
for (let i = 0; i < toRemove.length; i++) toRemove[i].remove();
|
|
874
415
|
if (moved) {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
if (anchor) {
|
|
885
|
-
parent.insertBefore(node, anchor);
|
|
886
|
-
}
|
|
887
|
-
else {
|
|
888
|
-
// Insert at end
|
|
889
|
-
let temp = anchor.nextSibling; // ?? 这里难道不是null?
|
|
890
|
-
while (temp && newElements.includes(temp)) {
|
|
891
|
-
temp = temp.nextSibling;
|
|
892
|
-
}
|
|
893
|
-
parent.insertBefore(node, temp);
|
|
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);
|
|
894
425
|
}
|
|
895
426
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
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--;
|
|
899
439
|
anchor = node;
|
|
900
440
|
}
|
|
901
|
-
}
|
|
902
|
-
else {
|
|
903
|
-
// No moves needed, just insert new nodes
|
|
441
|
+
} else {
|
|
904
442
|
let currentNode = anchor.nextSibling;
|
|
905
443
|
for (let i = 0; i < newLength; i++) {
|
|
906
444
|
const node = newElements[i];
|
|
907
|
-
|
|
908
|
-
parent.insertBefore(node, currentNode);
|
|
909
|
-
}
|
|
910
|
-
else {
|
|
911
|
-
currentNode = currentNode.nextSibling;
|
|
912
|
-
}
|
|
445
|
+
currentNode !== node ? parent.insertBefore(node, currentNode) : currentNode = currentNode.nextSibling;
|
|
913
446
|
}
|
|
914
447
|
}
|
|
915
|
-
// Update maps
|
|
916
448
|
nodeMap.clear();
|
|
917
449
|
for (let i = 0; i < newLength; i++) {
|
|
918
450
|
const itemKey = currentKey(newList[i], i, newList);
|
|
919
451
|
nodeMap.set(itemKey, newElements[i]);
|
|
920
452
|
}
|
|
921
|
-
anchor.__kt_for_list__ = newElements;
|
|
922
|
-
|
|
923
|
-
};
|
|
924
|
-
const { key: currentKey = (item) => item, map: currentMap = $identity } = props;
|
|
925
|
-
const listRef = toReactive(props.list).addOnChange(redraw);
|
|
926
|
-
const anchor = document.createComment('kt-for');
|
|
927
|
-
// Map to track rendered nodes by key
|
|
928
|
-
const nodeMap = new Map();
|
|
929
|
-
// Render initial list
|
|
930
|
-
const elements = [];
|
|
453
|
+
return anchor.__kt_for_list__ = newElements, anchor;
|
|
454
|
+
}), anchor = document.createComment("kt-for"), nodeMap = new Map, elements = [];
|
|
931
455
|
for (let index = 0; index < listRef.value.length; index++) {
|
|
932
|
-
const item = listRef.value[index];
|
|
933
|
-
|
|
934
|
-
const node = currentMap(item, index, listRef.value);
|
|
935
|
-
nodeMap.set(itemKey, node);
|
|
936
|
-
elements.push(node);
|
|
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);
|
|
937
458
|
}
|
|
938
|
-
anchor.__kt_for_list__ = elements;
|
|
939
|
-
$initRef(props, anchor);
|
|
940
|
-
return anchor;
|
|
941
|
-
}
|
|
942
|
-
// Longest Increasing Subsequence algorithm (optimized for diff)
|
|
943
|
-
function getSequence(arr) {
|
|
944
|
-
const p = arr.slice();
|
|
945
|
-
const result = [0];
|
|
946
|
-
let i, j, u, v, c;
|
|
947
|
-
const len = arr.length;
|
|
948
|
-
for (i = 0; i < len; i++) {
|
|
949
|
-
const arrI = arr[i];
|
|
950
|
-
if (arrI === -1)
|
|
951
|
-
continue;
|
|
952
|
-
j = result[result.length - 1];
|
|
953
|
-
if (arr[j] < arrI) {
|
|
954
|
-
p[i] = j;
|
|
955
|
-
result.push(i);
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
u = 0;
|
|
959
|
-
v = result.length - 1;
|
|
960
|
-
while (u < v) {
|
|
961
|
-
c = ((u + v) / 2) | 0;
|
|
962
|
-
if (arr[result[c]] < arrI) {
|
|
963
|
-
u = c + 1;
|
|
964
|
-
}
|
|
965
|
-
else {
|
|
966
|
-
v = c;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
if (arrI < arr[result[u]]) {
|
|
970
|
-
if (u > 0) {
|
|
971
|
-
p[i] = result[u - 1];
|
|
972
|
-
}
|
|
973
|
-
result[u] = i;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
u = result.length;
|
|
977
|
-
v = result[u - 1];
|
|
978
|
-
while (u-- > 0) {
|
|
979
|
-
result[u] = v;
|
|
980
|
-
v = p[v];
|
|
981
|
-
}
|
|
982
|
-
return result;
|
|
459
|
+
return anchor.__kt_for_list__ = elements, $initRef(props, anchor), anchor;
|
|
983
460
|
}
|
|
984
461
|
|
|
985
462
|
function KTConditional(condition, tagIf, propsIf, tagElse, propsElse) {
|
|
986
|
-
if (!isKT(condition))
|
|
987
|
-
return condition ? jsxh(tagIf, propsIf) : tagElse ? jsxh(tagElse, propsElse) : placeholder('kt-conditional');
|
|
988
|
-
}
|
|
463
|
+
if (!isKT(condition)) return condition ? jsxh(tagIf, propsIf) : tagElse ? jsxh(tagElse, propsElse) : placeholder("kt-conditional");
|
|
989
464
|
if (tagElse) {
|
|
990
465
|
let current = condition.value ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse);
|
|
991
|
-
condition.addOnChange(
|
|
466
|
+
return condition.addOnChange(newValue => {
|
|
992
467
|
const old = current;
|
|
993
|
-
current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse);
|
|
994
|
-
|
|
995
|
-
});
|
|
996
|
-
return current;
|
|
468
|
+
current = newValue ? jsxh(tagIf, propsIf) : jsxh(tagElse, propsElse), old.replaceWith(current);
|
|
469
|
+
}), current;
|
|
997
470
|
}
|
|
998
|
-
|
|
999
|
-
const dummy = placeholder(
|
|
471
|
+
{
|
|
472
|
+
const dummy = placeholder("kt-conditional");
|
|
1000
473
|
let current = condition.value ? jsxh(tagIf, propsIf) : dummy;
|
|
1001
|
-
condition.addOnChange(
|
|
474
|
+
return condition.addOnChange(newValue => {
|
|
1002
475
|
const old = current;
|
|
1003
|
-
current = newValue ? jsxh(tagIf, propsIf) : dummy;
|
|
1004
|
-
|
|
1005
|
-
});
|
|
1006
|
-
return current;
|
|
476
|
+
current = newValue ? jsxh(tagIf, propsIf) : dummy, old.replaceWith(current);
|
|
477
|
+
}), current;
|
|
1007
478
|
}
|
|
1008
479
|
}
|
|
1009
480
|
|