@ktjs/core 0.20.2 → 0.21.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.
@@ -1,5 +1,6 @@
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
@@ -9,6 +10,7 @@ const $throw = (message) => {
9
10
 
10
11
  // DOM manipulation utilities
11
12
  // # dom natives
13
+ const $replaceWith = Element.prototype.replaceWith;
12
14
  /**
13
15
  * & Remove `bind` because it is shockingly slower than wrapper
14
16
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -48,7 +50,7 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
48
50
 
49
51
  // Shared utilities and cached native methods for kt.js framework
50
52
  // Re-export all utilities
51
- Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
53
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
52
54
 
53
55
  const booleanHandler = (element, key, value) => {
54
56
  if (key in element) {
@@ -191,7 +193,6 @@ function applyContent(element, content) {
191
193
  }
192
194
  }
193
195
 
194
- document.createElement('div');
195
196
  const htmlCreator = (tag) => document.createElement(tag);
196
197
  const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
197
198
  const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
@@ -209,7 +210,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
209
210
  * ## About
210
211
  * @package @ktjs/core
211
212
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
212
- * @version 0.20.2 (Last Update: 2026.02.01 18:34:51.151)
213
+ * @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
213
214
  * @license MIT
214
215
  * @link https://github.com/baendlorel/kt.js
215
216
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -238,14 +239,6 @@ const h = (tag, attr, content) => {
238
239
  // * Handle content
239
240
  applyAttr(element, attr);
240
241
  applyContent(element, content);
241
- // if (tag === 'svg') {
242
- // tempWrapper.innerHTML = element.outerHTML;
243
- // return tempWrapper.firstChild as HTML<T>;
244
- // }
245
- // if (tag === 'math') {
246
- // tempWrapper.innerHTML = element.outerHTML;
247
- // return tempWrapper.firstChild as HTML<T>;
248
- // }
249
242
  return element;
250
243
  };
251
244
 
@@ -254,7 +247,13 @@ class KTRef {
254
247
  * Indicates that this is a KTRef instance
255
248
  */
256
249
  isKT = true;
250
+ /**
251
+ * @internal
252
+ */
257
253
  _value;
254
+ /**
255
+ * @internal
256
+ */
258
257
  _onChanges;
259
258
  constructor(_value, _onChanges) {
260
259
  this._value = _value;
@@ -296,37 +295,85 @@ class KTRef {
296
295
  return false;
297
296
  }
298
297
  }
298
+ const isKTRef = (obj) => {
299
+ return typeof obj === 'object' && obj !== null && obj.isKT === true;
300
+ };
299
301
  /**
300
302
  * Reference to the created HTML element.
303
+ * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
301
304
  * - can alse be used to store normal values, but it is not reactive.
302
305
  * @param value mostly an HTMLElement
303
306
  */
304
307
  function ref(value, onChange) {
305
308
  return new KTRef(value, onChange ? [onChange] : []);
306
309
  }
310
+ function kcollect() {
311
+ const newObj = {};
312
+ const entries = $entries(this);
313
+ for (let i = 0; i < entries.length; i++) {
314
+ const key = entries[i][0];
315
+ if (key === 'kcollect') {
316
+ continue;
317
+ }
318
+ newObj[key] = entries[i][1].value;
319
+ }
320
+ return newObj;
321
+ }
322
+ /**
323
+ * Make all first-level properties of the object a `KTRef`.
324
+ * - `obj.a.b` is not reactive
325
+ */
326
+ const surfaceRef = (obj) => {
327
+ const entries = $entries(obj);
328
+ const newObj = { kcollect };
329
+ for (let i = 0; i < entries.length; i++) {
330
+ newObj[entries[i][0]] = ref(entries[i][1]);
331
+ }
332
+ return newObj;
333
+ };
307
334
 
308
335
  const dummyRef = { value: null };
336
+ const create = (tag, props) => {
337
+ if (typeof tag === 'function') {
338
+ return tag(props);
339
+ }
340
+ else {
341
+ return h(tag, props, props.children);
342
+ }
343
+ };
344
+ const placeholder = () => document.createComment('k-if');
309
345
  /**
310
346
  * @param tag html tag or function component
311
347
  * @param props properties/attributes
312
348
  */
313
349
  function jsx(tag, props) {
314
- const ref = props.ref?.isKT ? props.ref : dummyRef;
350
+ const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
315
351
  let el;
316
- if ('k-if' in props && !props['k-if']) {
317
- // & make comment placeholder in case that ref might be redrawn later
318
- el = document.createComment('k-if');
319
- ref.value = el;
320
- return el;
321
- }
322
- // Handle function components
323
- if (typeof tag === 'function') {
324
- el = tag(props);
325
- }
326
- else {
327
- el = h(tag, props, props.children);
352
+ if ('k-if' in props) {
353
+ const kif = props['k-if'];
354
+ let condition = kif; // assume boolean by default
355
+ // Handle reactive k-if
356
+ if (isKTRef(kif)) {
357
+ kif.addOnChange((newValue, oldValue) => {
358
+ if (newValue === oldValue) {
359
+ return;
360
+ }
361
+ const oldEl = el;
362
+ el = newValue ? create(tag, props) : placeholder();
363
+ $replaceWith.call(oldEl, el);
364
+ maybeDummyRef.value = el;
365
+ });
366
+ condition = kif.value;
367
+ }
368
+ if (!condition) {
369
+ // & make comment placeholder in case that ref might be redrawn later
370
+ el = placeholder();
371
+ maybeDummyRef.value = el;
372
+ return el;
373
+ }
328
374
  }
329
- ref.value = el;
375
+ el = create(tag, props);
376
+ maybeDummyRef.value = el;
330
377
  return el;
331
378
  }
332
379
  /**
@@ -394,4 +441,4 @@ function createRedrawable(creator) {
394
441
  return elRef;
395
442
  }
396
443
 
397
- export { Fragment, KTRef, h as createElement, createRedrawable, jsx, jsxDEV, jsxs, ref };
444
+ export { Fragment, KTRef, h as createElement, createRedrawable, isKTRef, jsx, jsxDEV, jsxs, ref, surfaceRef };
@@ -13,8 +13,6 @@ declare class KTRef<T> {
13
13
  * Indicates that this is a KTRef instance
14
14
  */
15
15
  isKT: boolean;
16
- private _value;
17
- private _onChanges;
18
16
  constructor(_value: T, _onChanges: Array<RefChangeHandler<T>>);
19
17
  /**
20
18
  * If new value and old value are both nodes, the old one will be replaced in the DOM
@@ -25,6 +23,14 @@ declare class KTRef<T> {
25
23
  removeOnChange(callback: RefChangeHandler<T>): boolean;
26
24
  }
27
25
 
26
+ type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag
27
+ ? SVGElementTagNameMap[T]
28
+ : T extends HTMLTag
29
+ ? HTMLElementTagNameMap[T]
30
+ : T extends MathMLTag
31
+ ? MathMLElementTagNameMap[T]
32
+ : HTMLElement;
33
+
28
34
  type SingleContent = KTRef<any> | HTMLElement | Element | Node | string | number | boolean | null | undefined;
29
35
  type KTAvailableContent = SingleContent | KTAvailableContent[];
30
36
  type KTRawContent = KTAvailableContent | Promise<KTAvailableContent>;
@@ -38,7 +44,14 @@ interface KTBaseAttribute {
38
44
 
39
45
  // # kt-specific attributes
40
46
  ref?: KTRef<JSX.Element>;
47
+
48
+ // todo 是否要让k-if是KTRef的时候具备响应能力?
49
+ /**
50
+ * If a `KTRef` is bound, it will be reactive; otherwise, it will be static.
51
+ */
41
52
  'k-if'?: any;
53
+ // todo k-model如何指定value还是checked还是别的什么?
54
+ 'k-model'?: KTRef<any>;
42
55
 
43
56
  // # normal HTML attributes
44
57
  id?: string;
@@ -99,7 +112,6 @@ type KTPrefixedEventHandlers = {
99
112
 
100
113
  type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
101
114
 
102
- type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag ? SVGElementTagNameMap[T] : T extends HTMLTag ? HTMLElementTagNameMap[T] : T extends MathMLTag ? MathMLElementTagNameMap[T] : HTMLElement;
103
115
  /**
104
116
  * Create an enhanced HTMLElement.
105
117
  * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
@@ -110,7 +122,7 @@ type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SV
110
122
  * ## About
111
123
  * @package @ktjs/core
112
124
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
113
- * @version 0.20.2 (Last Update: 2026.02.01 18:34:51.151)
125
+ * @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
114
126
  * @license MIT
115
127
  * @link https://github.com/baendlorel/kt.js
116
128
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -9,6 +9,7 @@ const $throw = (message) => {
9
9
 
10
10
  // DOM manipulation utilities
11
11
  // # dom natives
12
+ const $replaceWith = Element.prototype.replaceWith;
12
13
  /**
13
14
  * & Remove `bind` because it is shockingly slower than wrapper
14
15
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -48,7 +49,7 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
48
49
 
49
50
  // Shared utilities and cached native methods for kt.js framework
50
51
  // Re-export all utilities
51
- Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
52
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
52
53
 
53
54
  const booleanHandler = (element, key, value) => {
54
55
  if (key in element) {
@@ -191,7 +192,6 @@ function applyContent(element, content) {
191
192
  }
192
193
  }
193
194
 
194
- document.createElement('div');
195
195
  const htmlCreator = (tag) => document.createElement(tag);
196
196
  const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
197
197
  const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
@@ -209,7 +209,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
209
209
  * ## About
210
210
  * @package @ktjs/core
211
211
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
212
- * @version 0.20.2 (Last Update: 2026.02.01 18:34:51.151)
212
+ * @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
213
213
  * @license MIT
214
214
  * @link https://github.com/baendlorel/kt.js
215
215
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -238,14 +238,6 @@ const h = (tag, attr, content) => {
238
238
  // * Handle content
239
239
  applyAttr(element, attr);
240
240
  applyContent(element, content);
241
- // if (tag === 'svg') {
242
- // tempWrapper.innerHTML = element.outerHTML;
243
- // return tempWrapper.firstChild as HTML<T>;
244
- // }
245
- // if (tag === 'math') {
246
- // tempWrapper.innerHTML = element.outerHTML;
247
- // return tempWrapper.firstChild as HTML<T>;
248
- // }
249
241
  return element;
250
242
  };
251
243
 
@@ -254,7 +246,13 @@ class KTRef {
254
246
  * Indicates that this is a KTRef instance
255
247
  */
256
248
  isKT = true;
249
+ /**
250
+ * @internal
251
+ */
257
252
  _value;
253
+ /**
254
+ * @internal
255
+ */
258
256
  _onChanges;
259
257
  constructor(_value, _onChanges) {
260
258
  this._value = _value;
@@ -296,8 +294,12 @@ class KTRef {
296
294
  return false;
297
295
  }
298
296
  }
297
+ const isKTRef = (obj) => {
298
+ return typeof obj === 'object' && obj !== null && obj.isKT === true;
299
+ };
299
300
  /**
300
301
  * Reference to the created HTML element.
302
+ * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
301
303
  * - can alse be used to store normal values, but it is not reactive.
302
304
  * @param value mostly an HTMLElement
303
305
  */
@@ -306,27 +308,47 @@ function ref(value, onChange) {
306
308
  }
307
309
 
308
310
  const dummyRef = { value: null };
311
+ const create = (tag, props) => {
312
+ if (typeof tag === 'function') {
313
+ return tag(props);
314
+ }
315
+ else {
316
+ return h(tag, props, props.children);
317
+ }
318
+ };
319
+ const placeholder = () => document.createComment('k-if');
309
320
  /**
310
321
  * @param tag html tag or function component
311
322
  * @param props properties/attributes
312
323
  */
313
324
  function jsx(tag, props) {
314
- const ref = props.ref?.isKT ? props.ref : dummyRef;
325
+ const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
315
326
  let el;
316
- if ('k-if' in props && !props['k-if']) {
317
- // & make comment placeholder in case that ref might be redrawn later
318
- el = document.createComment('k-if');
319
- ref.value = el;
320
- return el;
321
- }
322
- // Handle function components
323
- if (typeof tag === 'function') {
324
- el = tag(props);
325
- }
326
- else {
327
- el = h(tag, props, props.children);
327
+ if ('k-if' in props) {
328
+ const kif = props['k-if'];
329
+ let condition = kif; // assume boolean by default
330
+ // Handle reactive k-if
331
+ if (isKTRef(kif)) {
332
+ kif.addOnChange((newValue, oldValue) => {
333
+ if (newValue === oldValue) {
334
+ return;
335
+ }
336
+ const oldEl = el;
337
+ el = newValue ? create(tag, props) : placeholder();
338
+ $replaceWith.call(oldEl, el);
339
+ maybeDummyRef.value = el;
340
+ });
341
+ condition = kif.value;
342
+ }
343
+ if (!condition) {
344
+ // & make comment placeholder in case that ref might be redrawn later
345
+ el = placeholder();
346
+ maybeDummyRef.value = el;
347
+ return el;
348
+ }
328
349
  }
329
- ref.value = el;
350
+ el = create(tag, props);
351
+ maybeDummyRef.value = el;
330
352
  return el;
331
353
  }
332
354
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.20.2",
3
+ "version": "0.21.1",
4
4
  "description": "Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -44,7 +44,7 @@
44
44
  "directory": "packages/core"
45
45
  },
46
46
  "dependencies": {
47
- "@ktjs/shared": "0.20.0"
47
+ "@ktjs/shared": "0.20.2"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "rollup -c rollup.config.mjs",