@ktjs/core 0.20.3 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -453
- package/dist/index.d.ts +36 -4
- package/dist/index.iife.js +161 -89
- package/dist/index.legacy.js +159 -88
- package/dist/index.mjs +160 -90
- package/dist/jsx/index.d.ts +36 -3
- package/dist/jsx/index.mjs +160 -90
- package/dist/jsx/jsx-runtime.d.ts +19 -2
- package/dist/jsx/jsx-runtime.mjs +134 -89
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
// Cached native methods for performance optimization
|
|
2
2
|
const $isArray = Array.isArray;
|
|
3
|
+
const $entries = Object.entries;
|
|
3
4
|
const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
4
5
|
|
|
5
6
|
// Error handling utilities
|
|
6
7
|
const $throw = (message) => {
|
|
7
8
|
throw new Error('@ktjs/shared: ' + message);
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
// DOM manipulation utilities
|
|
11
|
-
// # dom natives
|
|
12
10
|
/**
|
|
13
11
|
* & Remove `bind` because it is shockingly slower than wrapper
|
|
14
12
|
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
@@ -48,7 +46,97 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
|
|
|
48
46
|
|
|
49
47
|
// Shared utilities and cached native methods for kt.js framework
|
|
50
48
|
// Re-export all utilities
|
|
51
|
-
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.
|
|
49
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
|
|
50
|
+
|
|
51
|
+
class KTRef {
|
|
52
|
+
/**
|
|
53
|
+
* Indicates that this is a KTRef instance
|
|
54
|
+
*/
|
|
55
|
+
isKT = true;
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
_value;
|
|
60
|
+
/**
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
_onChanges;
|
|
64
|
+
constructor(_value, _onChanges) {
|
|
65
|
+
this._value = _value;
|
|
66
|
+
this._onChanges = _onChanges;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
70
|
+
*/
|
|
71
|
+
get value() {
|
|
72
|
+
return this._value;
|
|
73
|
+
}
|
|
74
|
+
set value(newValue) {
|
|
75
|
+
if (newValue === this._value) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// replace the old node with the new one in the DOM if both are nodes
|
|
79
|
+
if (this._value instanceof Node && newValue instanceof Node) {
|
|
80
|
+
if (newValue.contains(this._value)) {
|
|
81
|
+
this._value.remove();
|
|
82
|
+
}
|
|
83
|
+
this._value.replaceWith(newValue);
|
|
84
|
+
}
|
|
85
|
+
const oldValue = this._value;
|
|
86
|
+
this._value = newValue;
|
|
87
|
+
for (let i = 0; i < this._onChanges.length; i++) {
|
|
88
|
+
this._onChanges[i](newValue, oldValue);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
addOnChange(callback) {
|
|
92
|
+
this._onChanges.push(callback);
|
|
93
|
+
}
|
|
94
|
+
removeOnChange(callback) {
|
|
95
|
+
for (let i = this._onChanges.length - 1; i >= 0; i--) {
|
|
96
|
+
if (this._onChanges[i] === callback) {
|
|
97
|
+
this._onChanges.splice(i, 1);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const isKTRef = (obj) => {
|
|
105
|
+
return typeof obj === 'object' && obj !== null && obj.isKT === true;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Reference to the created HTML element.
|
|
109
|
+
* - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
|
|
110
|
+
* - can alse be used to store normal values, but it is not reactive.
|
|
111
|
+
* @param value mostly an HTMLElement
|
|
112
|
+
*/
|
|
113
|
+
function ref(value, onChange) {
|
|
114
|
+
return new KTRef(value, onChange ? [onChange] : []);
|
|
115
|
+
}
|
|
116
|
+
function kcollect() {
|
|
117
|
+
const newObj = {};
|
|
118
|
+
const entries = $entries(this);
|
|
119
|
+
for (let i = 0; i < entries.length; i++) {
|
|
120
|
+
const key = entries[i][0];
|
|
121
|
+
if (key === 'kcollect') {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
newObj[key] = entries[i][1].value;
|
|
125
|
+
}
|
|
126
|
+
return newObj;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Make all first-level properties of the object a `KTRef`.
|
|
130
|
+
* - `obj.a.b` is not reactive
|
|
131
|
+
*/
|
|
132
|
+
const surfaceRef = (obj) => {
|
|
133
|
+
const entries = $entries(obj);
|
|
134
|
+
const newObj = { kcollect };
|
|
135
|
+
for (let i = 0; i < entries.length; i++) {
|
|
136
|
+
newObj[entries[i][0]] = ref(entries[i][1]);
|
|
137
|
+
}
|
|
138
|
+
return newObj;
|
|
139
|
+
};
|
|
52
140
|
|
|
53
141
|
const booleanHandler = (element, key, value) => {
|
|
54
142
|
if (key in element) {
|
|
@@ -114,6 +202,7 @@ function attrIsObject(element, attr) {
|
|
|
114
202
|
key === 'style' ||
|
|
115
203
|
key === 'children' ||
|
|
116
204
|
key === 'k-if' ||
|
|
205
|
+
key.startsWith('k-model') ||
|
|
117
206
|
key === 'ref') {
|
|
118
207
|
continue;
|
|
119
208
|
}
|
|
@@ -191,7 +280,29 @@ function applyContent(element, content) {
|
|
|
191
280
|
}
|
|
192
281
|
}
|
|
193
282
|
|
|
194
|
-
|
|
283
|
+
function register(element, valueRef, propName, eventName) {
|
|
284
|
+
element[propName] = valueRef.value; // initialize
|
|
285
|
+
valueRef.addOnChange((newValue) => (element[propName] = newValue));
|
|
286
|
+
element.addEventListener(eventName, () => (valueRef.value = element[propName]));
|
|
287
|
+
}
|
|
288
|
+
function applyModel(element, valueRef) {
|
|
289
|
+
if (element instanceof HTMLInputElement) {
|
|
290
|
+
if (element.type === 'radio' || element.type === 'checkbox') {
|
|
291
|
+
register(element, valueRef, 'checked', 'change');
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
register(element, valueRef, 'value', 'input');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (element instanceof HTMLSelectElement) {
|
|
298
|
+
register(element, valueRef, 'value', 'change');
|
|
299
|
+
}
|
|
300
|
+
else if (element instanceof HTMLTextAreaElement) {
|
|
301
|
+
register(element, valueRef, 'value', 'input');
|
|
302
|
+
}
|
|
303
|
+
console.warn('[kt.js warn] not supported element for k-model:', element.tagName);
|
|
304
|
+
}
|
|
305
|
+
|
|
195
306
|
const htmlCreator = (tag) => document.createElement(tag);
|
|
196
307
|
const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
197
308
|
const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
|
|
@@ -209,7 +320,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
|
|
|
209
320
|
* ## About
|
|
210
321
|
* @package @ktjs/core
|
|
211
322
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
212
|
-
* @version 0.
|
|
323
|
+
* @version 0.22.0 (Last Update: 2026.02.02 17:11:04.703)
|
|
213
324
|
* @license MIT
|
|
214
325
|
* @link https://github.com/baendlorel/kt.js
|
|
215
326
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -238,101 +349,60 @@ const h = (tag, attr, content) => {
|
|
|
238
349
|
// * Handle content
|
|
239
350
|
applyAttr(element, attr);
|
|
240
351
|
applyContent(element, content);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// if (tag === 'math') {
|
|
246
|
-
// tempWrapper.innerHTML = element.outerHTML;
|
|
247
|
-
// return tempWrapper.firstChild as HTML<T>;
|
|
248
|
-
// }
|
|
249
|
-
return element;
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
class KTRef {
|
|
253
|
-
/**
|
|
254
|
-
* Indicates that this is a KTRef instance
|
|
255
|
-
*/
|
|
256
|
-
isKT = true;
|
|
257
|
-
/**
|
|
258
|
-
* @internal
|
|
259
|
-
*/
|
|
260
|
-
_value;
|
|
261
|
-
/**
|
|
262
|
-
* @internal
|
|
263
|
-
*/
|
|
264
|
-
_onChanges;
|
|
265
|
-
constructor(_value, _onChanges) {
|
|
266
|
-
this._value = _value;
|
|
267
|
-
this._onChanges = _onChanges;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
271
|
-
*/
|
|
272
|
-
get value() {
|
|
273
|
-
return this._value;
|
|
274
|
-
}
|
|
275
|
-
set value(newValue) {
|
|
276
|
-
if (newValue === this._value) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// replace the old node with the new one in the DOM if both are nodes
|
|
280
|
-
if (this._value instanceof Node && newValue instanceof Node) {
|
|
281
|
-
if (newValue.contains(this._value)) {
|
|
282
|
-
this._value.remove();
|
|
283
|
-
}
|
|
284
|
-
this._value.replaceWith(newValue);
|
|
352
|
+
if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
|
|
353
|
+
const kmodel = attr['k-model'];
|
|
354
|
+
if (isKTRef(kmodel)) {
|
|
355
|
+
applyModel(element, kmodel);
|
|
285
356
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
for (let i = 0; i < this._onChanges.length; i++) {
|
|
289
|
-
this._onChanges[i](newValue, oldValue);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
addOnChange(callback) {
|
|
293
|
-
this._onChanges.push(callback);
|
|
294
|
-
}
|
|
295
|
-
removeOnChange(callback) {
|
|
296
|
-
for (let i = this._onChanges.length - 1; i >= 0; i--) {
|
|
297
|
-
if (this._onChanges[i] === callback) {
|
|
298
|
-
this._onChanges.splice(i, 1);
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
357
|
+
else {
|
|
358
|
+
$throw('k-model value must be a KTRef.');
|
|
301
359
|
}
|
|
302
|
-
return false;
|
|
303
360
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* Reference to the created HTML element.
|
|
307
|
-
* - can alse be used to store normal values, but it is not reactive.
|
|
308
|
-
* @param value mostly an HTMLElement
|
|
309
|
-
*/
|
|
310
|
-
function ref(value, onChange) {
|
|
311
|
-
return new KTRef(value, onChange ? [onChange] : []);
|
|
312
|
-
}
|
|
361
|
+
return element;
|
|
362
|
+
};
|
|
313
363
|
|
|
314
364
|
const dummyRef = { value: null };
|
|
365
|
+
const create = (tag, props) => {
|
|
366
|
+
if (typeof tag === 'function') {
|
|
367
|
+
return tag(props);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return h(tag, props, props.children);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
const placeholder = () => document.createComment('k-if');
|
|
315
374
|
/**
|
|
316
375
|
* @param tag html tag or function component
|
|
317
376
|
* @param props properties/attributes
|
|
318
377
|
*/
|
|
319
378
|
function jsx(tag, props) {
|
|
320
|
-
const
|
|
379
|
+
const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
|
|
321
380
|
let el;
|
|
322
|
-
if ('k-if' in props
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
381
|
+
if ('k-if' in props) {
|
|
382
|
+
const kif = props['k-if'];
|
|
383
|
+
let condition = kif; // assume boolean by default
|
|
384
|
+
// Handle reactive k-if
|
|
385
|
+
if (isKTRef(kif)) {
|
|
386
|
+
kif.addOnChange((newValue, oldValue) => {
|
|
387
|
+
if (newValue === oldValue) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const oldEl = el;
|
|
391
|
+
el = newValue ? create(tag, props) : placeholder();
|
|
392
|
+
oldEl.replaceWith(el);
|
|
393
|
+
maybeDummyRef.value = el;
|
|
394
|
+
});
|
|
395
|
+
condition = kif.value;
|
|
396
|
+
}
|
|
397
|
+
if (!condition) {
|
|
398
|
+
// & make comment placeholder in case that ref might be redrawn later
|
|
399
|
+
el = placeholder();
|
|
400
|
+
maybeDummyRef.value = el;
|
|
401
|
+
return el;
|
|
402
|
+
}
|
|
334
403
|
}
|
|
335
|
-
|
|
404
|
+
el = create(tag, props);
|
|
405
|
+
maybeDummyRef.value = el;
|
|
336
406
|
return el;
|
|
337
407
|
}
|
|
338
408
|
/**
|
|
@@ -624,4 +694,4 @@ function getSequence(arr) {
|
|
|
624
694
|
return result;
|
|
625
695
|
}
|
|
626
696
|
|
|
627
|
-
export { Fragment, KTAsync, KTFor, KTRef, h as createElement, createRedrawable, h, jsx, jsxDEV, jsxs, ref };
|
|
697
|
+
export { Fragment, KTAsync, KTFor, KTRef, h as createElement, createRedrawable, h, isKTRef, jsx, jsxDEV, jsxs, ref, surfaceRef };
|
package/dist/jsx/index.d.ts
CHANGED
|
@@ -22,12 +22,35 @@ declare class KTRef<T> {
|
|
|
22
22
|
addOnChange(callback: RefChangeHandler<T>): void;
|
|
23
23
|
removeOnChange(callback: RefChangeHandler<T>): boolean;
|
|
24
24
|
}
|
|
25
|
+
declare const isKTRef: <T = any>(obj: any) => obj is KTRef<T>;
|
|
25
26
|
/**
|
|
26
27
|
* Reference to the created HTML element.
|
|
28
|
+
* - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
|
|
27
29
|
* - can alse be used to store normal values, but it is not reactive.
|
|
28
30
|
* @param value mostly an HTMLElement
|
|
29
31
|
*/
|
|
30
32
|
declare function ref<T = JSX.Element>(value?: T, onChange?: RefChangeHandler<T>): KTRef<T>;
|
|
33
|
+
type KTSurfaceRef<T extends Object> = {
|
|
34
|
+
[K in keyof T]: KTRef<T[K]>;
|
|
35
|
+
} & {
|
|
36
|
+
/**
|
|
37
|
+
* Get the dereferenced object like the original one
|
|
38
|
+
*/
|
|
39
|
+
kcollect: () => T;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Make all first-level properties of the object a `KTRef`.
|
|
43
|
+
* - `obj.a.b` is not reactive
|
|
44
|
+
*/
|
|
45
|
+
declare const surfaceRef: <T extends Object>(obj: T) => KTSurfaceRef<T>;
|
|
46
|
+
|
|
47
|
+
type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag
|
|
48
|
+
? SVGElementTagNameMap[T]
|
|
49
|
+
: T extends HTMLTag
|
|
50
|
+
? HTMLElementTagNameMap[T]
|
|
51
|
+
: T extends MathMLTag
|
|
52
|
+
? MathMLElementTagNameMap[T]
|
|
53
|
+
: HTMLElement;
|
|
31
54
|
|
|
32
55
|
type SingleContent = KTRef<any> | HTMLElement | Element | Node | string | number | boolean | null | undefined;
|
|
33
56
|
type KTAvailableContent = SingleContent | KTAvailableContent[];
|
|
@@ -42,8 +65,18 @@ interface KTBaseAttribute {
|
|
|
42
65
|
|
|
43
66
|
// # kt-specific attributes
|
|
44
67
|
ref?: KTRef<JSX.Element>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* If a `KTRef` is bound, it will be reactive; otherwise, it will be static.
|
|
71
|
+
*/
|
|
45
72
|
'k-if'?: any;
|
|
46
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Register two-way data binding between an input element and a KTRef.
|
|
76
|
+
* - Default to regist `input` event and `value` property(`checked` for checkboxes and radios).
|
|
77
|
+
*/
|
|
78
|
+
'k-model'?: KTRef<any>;
|
|
79
|
+
|
|
47
80
|
// # normal HTML attributes
|
|
48
81
|
id?: string;
|
|
49
82
|
class?: string;
|
|
@@ -103,7 +136,6 @@ type KTPrefixedEventHandlers = {
|
|
|
103
136
|
|
|
104
137
|
type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
|
|
105
138
|
|
|
106
|
-
type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag ? SVGElementTagNameMap[T] : T extends HTMLTag ? HTMLElementTagNameMap[T] : T extends MathMLTag ? MathMLElementTagNameMap[T] : HTMLElement;
|
|
107
139
|
/**
|
|
108
140
|
* Create an enhanced HTMLElement.
|
|
109
141
|
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
@@ -114,7 +146,7 @@ type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SV
|
|
|
114
146
|
* ## About
|
|
115
147
|
* @package @ktjs/core
|
|
116
148
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
117
|
-
* @version 0.
|
|
149
|
+
* @version 0.22.0 (Last Update: 2026.02.02 17:11:04.703)
|
|
118
150
|
* @license MIT
|
|
119
151
|
* @link https://github.com/baendlorel/kt.js
|
|
120
152
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -1393,4 +1425,5 @@ declare global {
|
|
|
1393
1425
|
}
|
|
1394
1426
|
}
|
|
1395
1427
|
|
|
1396
|
-
export { Fragment, KTRef, h as createElement, createRedrawable, jsx, jsxDEV, jsxs, ref };
|
|
1428
|
+
export { Fragment, KTRef, h as createElement, createRedrawable, isKTRef, jsx, jsxDEV, jsxs, ref, surfaceRef };
|
|
1429
|
+
export type { KTSurfaceRef };
|
package/dist/jsx/index.mjs
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
// Cached native methods for performance optimization
|
|
2
2
|
const $isArray = Array.isArray;
|
|
3
|
+
const $entries = Object.entries;
|
|
3
4
|
const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
4
5
|
|
|
5
6
|
// Error handling utilities
|
|
6
7
|
const $throw = (message) => {
|
|
7
8
|
throw new Error('@ktjs/shared: ' + message);
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
// DOM manipulation utilities
|
|
11
|
-
// # dom natives
|
|
12
10
|
/**
|
|
13
11
|
* & Remove `bind` because it is shockingly slower than wrapper
|
|
14
12
|
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
@@ -48,7 +46,97 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
|
|
|
48
46
|
|
|
49
47
|
// Shared utilities and cached native methods for kt.js framework
|
|
50
48
|
// Re-export all utilities
|
|
51
|
-
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.
|
|
49
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
|
|
50
|
+
|
|
51
|
+
class KTRef {
|
|
52
|
+
/**
|
|
53
|
+
* Indicates that this is a KTRef instance
|
|
54
|
+
*/
|
|
55
|
+
isKT = true;
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
_value;
|
|
60
|
+
/**
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
_onChanges;
|
|
64
|
+
constructor(_value, _onChanges) {
|
|
65
|
+
this._value = _value;
|
|
66
|
+
this._onChanges = _onChanges;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
70
|
+
*/
|
|
71
|
+
get value() {
|
|
72
|
+
return this._value;
|
|
73
|
+
}
|
|
74
|
+
set value(newValue) {
|
|
75
|
+
if (newValue === this._value) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// replace the old node with the new one in the DOM if both are nodes
|
|
79
|
+
if (this._value instanceof Node && newValue instanceof Node) {
|
|
80
|
+
if (newValue.contains(this._value)) {
|
|
81
|
+
this._value.remove();
|
|
82
|
+
}
|
|
83
|
+
this._value.replaceWith(newValue);
|
|
84
|
+
}
|
|
85
|
+
const oldValue = this._value;
|
|
86
|
+
this._value = newValue;
|
|
87
|
+
for (let i = 0; i < this._onChanges.length; i++) {
|
|
88
|
+
this._onChanges[i](newValue, oldValue);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
addOnChange(callback) {
|
|
92
|
+
this._onChanges.push(callback);
|
|
93
|
+
}
|
|
94
|
+
removeOnChange(callback) {
|
|
95
|
+
for (let i = this._onChanges.length - 1; i >= 0; i--) {
|
|
96
|
+
if (this._onChanges[i] === callback) {
|
|
97
|
+
this._onChanges.splice(i, 1);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const isKTRef = (obj) => {
|
|
105
|
+
return typeof obj === 'object' && obj !== null && obj.isKT === true;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Reference to the created HTML element.
|
|
109
|
+
* - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
|
|
110
|
+
* - can alse be used to store normal values, but it is not reactive.
|
|
111
|
+
* @param value mostly an HTMLElement
|
|
112
|
+
*/
|
|
113
|
+
function ref(value, onChange) {
|
|
114
|
+
return new KTRef(value, onChange ? [onChange] : []);
|
|
115
|
+
}
|
|
116
|
+
function kcollect() {
|
|
117
|
+
const newObj = {};
|
|
118
|
+
const entries = $entries(this);
|
|
119
|
+
for (let i = 0; i < entries.length; i++) {
|
|
120
|
+
const key = entries[i][0];
|
|
121
|
+
if (key === 'kcollect') {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
newObj[key] = entries[i][1].value;
|
|
125
|
+
}
|
|
126
|
+
return newObj;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Make all first-level properties of the object a `KTRef`.
|
|
130
|
+
* - `obj.a.b` is not reactive
|
|
131
|
+
*/
|
|
132
|
+
const surfaceRef = (obj) => {
|
|
133
|
+
const entries = $entries(obj);
|
|
134
|
+
const newObj = { kcollect };
|
|
135
|
+
for (let i = 0; i < entries.length; i++) {
|
|
136
|
+
newObj[entries[i][0]] = ref(entries[i][1]);
|
|
137
|
+
}
|
|
138
|
+
return newObj;
|
|
139
|
+
};
|
|
52
140
|
|
|
53
141
|
const booleanHandler = (element, key, value) => {
|
|
54
142
|
if (key in element) {
|
|
@@ -114,6 +202,7 @@ function attrIsObject(element, attr) {
|
|
|
114
202
|
key === 'style' ||
|
|
115
203
|
key === 'children' ||
|
|
116
204
|
key === 'k-if' ||
|
|
205
|
+
key.startsWith('k-model') ||
|
|
117
206
|
key === 'ref') {
|
|
118
207
|
continue;
|
|
119
208
|
}
|
|
@@ -191,7 +280,29 @@ function applyContent(element, content) {
|
|
|
191
280
|
}
|
|
192
281
|
}
|
|
193
282
|
|
|
194
|
-
|
|
283
|
+
function register(element, valueRef, propName, eventName) {
|
|
284
|
+
element[propName] = valueRef.value; // initialize
|
|
285
|
+
valueRef.addOnChange((newValue) => (element[propName] = newValue));
|
|
286
|
+
element.addEventListener(eventName, () => (valueRef.value = element[propName]));
|
|
287
|
+
}
|
|
288
|
+
function applyModel(element, valueRef) {
|
|
289
|
+
if (element instanceof HTMLInputElement) {
|
|
290
|
+
if (element.type === 'radio' || element.type === 'checkbox') {
|
|
291
|
+
register(element, valueRef, 'checked', 'change');
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
register(element, valueRef, 'value', 'input');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (element instanceof HTMLSelectElement) {
|
|
298
|
+
register(element, valueRef, 'value', 'change');
|
|
299
|
+
}
|
|
300
|
+
else if (element instanceof HTMLTextAreaElement) {
|
|
301
|
+
register(element, valueRef, 'value', 'input');
|
|
302
|
+
}
|
|
303
|
+
console.warn('[kt.js warn] not supported element for k-model:', element.tagName);
|
|
304
|
+
}
|
|
305
|
+
|
|
195
306
|
const htmlCreator = (tag) => document.createElement(tag);
|
|
196
307
|
const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
197
308
|
const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
|
|
@@ -209,7 +320,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
|
|
|
209
320
|
* ## About
|
|
210
321
|
* @package @ktjs/core
|
|
211
322
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
212
|
-
* @version 0.
|
|
323
|
+
* @version 0.22.0 (Last Update: 2026.02.02 17:11:04.703)
|
|
213
324
|
* @license MIT
|
|
214
325
|
* @link https://github.com/baendlorel/kt.js
|
|
215
326
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -238,101 +349,60 @@ const h = (tag, attr, content) => {
|
|
|
238
349
|
// * Handle content
|
|
239
350
|
applyAttr(element, attr);
|
|
240
351
|
applyContent(element, content);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// if (tag === 'math') {
|
|
246
|
-
// tempWrapper.innerHTML = element.outerHTML;
|
|
247
|
-
// return tempWrapper.firstChild as HTML<T>;
|
|
248
|
-
// }
|
|
249
|
-
return element;
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
class KTRef {
|
|
253
|
-
/**
|
|
254
|
-
* Indicates that this is a KTRef instance
|
|
255
|
-
*/
|
|
256
|
-
isKT = true;
|
|
257
|
-
/**
|
|
258
|
-
* @internal
|
|
259
|
-
*/
|
|
260
|
-
_value;
|
|
261
|
-
/**
|
|
262
|
-
* @internal
|
|
263
|
-
*/
|
|
264
|
-
_onChanges;
|
|
265
|
-
constructor(_value, _onChanges) {
|
|
266
|
-
this._value = _value;
|
|
267
|
-
this._onChanges = _onChanges;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* If new value and old value are both nodes, the old one will be replaced in the DOM
|
|
271
|
-
*/
|
|
272
|
-
get value() {
|
|
273
|
-
return this._value;
|
|
274
|
-
}
|
|
275
|
-
set value(newValue) {
|
|
276
|
-
if (newValue === this._value) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// replace the old node with the new one in the DOM if both are nodes
|
|
280
|
-
if (this._value instanceof Node && newValue instanceof Node) {
|
|
281
|
-
if (newValue.contains(this._value)) {
|
|
282
|
-
this._value.remove();
|
|
283
|
-
}
|
|
284
|
-
this._value.replaceWith(newValue);
|
|
352
|
+
if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
|
|
353
|
+
const kmodel = attr['k-model'];
|
|
354
|
+
if (isKTRef(kmodel)) {
|
|
355
|
+
applyModel(element, kmodel);
|
|
285
356
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
for (let i = 0; i < this._onChanges.length; i++) {
|
|
289
|
-
this._onChanges[i](newValue, oldValue);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
addOnChange(callback) {
|
|
293
|
-
this._onChanges.push(callback);
|
|
294
|
-
}
|
|
295
|
-
removeOnChange(callback) {
|
|
296
|
-
for (let i = this._onChanges.length - 1; i >= 0; i--) {
|
|
297
|
-
if (this._onChanges[i] === callback) {
|
|
298
|
-
this._onChanges.splice(i, 1);
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
357
|
+
else {
|
|
358
|
+
$throw('k-model value must be a KTRef.');
|
|
301
359
|
}
|
|
302
|
-
return false;
|
|
303
360
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* Reference to the created HTML element.
|
|
307
|
-
* - can alse be used to store normal values, but it is not reactive.
|
|
308
|
-
* @param value mostly an HTMLElement
|
|
309
|
-
*/
|
|
310
|
-
function ref(value, onChange) {
|
|
311
|
-
return new KTRef(value, onChange ? [onChange] : []);
|
|
312
|
-
}
|
|
361
|
+
return element;
|
|
362
|
+
};
|
|
313
363
|
|
|
314
364
|
const dummyRef = { value: null };
|
|
365
|
+
const create = (tag, props) => {
|
|
366
|
+
if (typeof tag === 'function') {
|
|
367
|
+
return tag(props);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return h(tag, props, props.children);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
const placeholder = () => document.createComment('k-if');
|
|
315
374
|
/**
|
|
316
375
|
* @param tag html tag or function component
|
|
317
376
|
* @param props properties/attributes
|
|
318
377
|
*/
|
|
319
378
|
function jsx(tag, props) {
|
|
320
|
-
const
|
|
379
|
+
const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
|
|
321
380
|
let el;
|
|
322
|
-
if ('k-if' in props
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
381
|
+
if ('k-if' in props) {
|
|
382
|
+
const kif = props['k-if'];
|
|
383
|
+
let condition = kif; // assume boolean by default
|
|
384
|
+
// Handle reactive k-if
|
|
385
|
+
if (isKTRef(kif)) {
|
|
386
|
+
kif.addOnChange((newValue, oldValue) => {
|
|
387
|
+
if (newValue === oldValue) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const oldEl = el;
|
|
391
|
+
el = newValue ? create(tag, props) : placeholder();
|
|
392
|
+
oldEl.replaceWith(el);
|
|
393
|
+
maybeDummyRef.value = el;
|
|
394
|
+
});
|
|
395
|
+
condition = kif.value;
|
|
396
|
+
}
|
|
397
|
+
if (!condition) {
|
|
398
|
+
// & make comment placeholder in case that ref might be redrawn later
|
|
399
|
+
el = placeholder();
|
|
400
|
+
maybeDummyRef.value = el;
|
|
401
|
+
return el;
|
|
402
|
+
}
|
|
334
403
|
}
|
|
335
|
-
|
|
404
|
+
el = create(tag, props);
|
|
405
|
+
maybeDummyRef.value = el;
|
|
336
406
|
return el;
|
|
337
407
|
}
|
|
338
408
|
/**
|
|
@@ -400,4 +470,4 @@ function createRedrawable(creator) {
|
|
|
400
470
|
return elRef;
|
|
401
471
|
}
|
|
402
472
|
|
|
403
|
-
export { Fragment, KTRef, h as createElement, createRedrawable, jsx, jsxDEV, jsxs, ref };
|
|
473
|
+
export { Fragment, KTRef, h as createElement, createRedrawable, isKTRef, jsx, jsxDEV, jsxs, ref, surfaceRef };
|