@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/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.0' });
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
- document.createElement('div');
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.20.3 (Last Update: 2026.02.01 18:38:02.198)
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
- // 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
- 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
- const oldValue = this._value;
287
- this._value = newValue;
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 ref = props.ref?.isKT ? props.ref : dummyRef;
379
+ const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
321
380
  let el;
322
- if ('k-if' in props && !props['k-if']) {
323
- // & make comment placeholder in case that ref might be redrawn later
324
- el = document.createComment('k-if');
325
- ref.value = el;
326
- return el;
327
- }
328
- // Handle function components
329
- if (typeof tag === 'function') {
330
- el = tag(props);
331
- }
332
- else {
333
- el = h(tag, props, props.children);
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
- ref.value = el;
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 };
@@ -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.20.3 (Last Update: 2026.02.01 18:38:02.198)
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 };
@@ -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.0' });
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
- document.createElement('div');
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.20.3 (Last Update: 2026.02.01 18:38:02.198)
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
- // 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
- 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
- const oldValue = this._value;
287
- this._value = newValue;
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 ref = props.ref?.isKT ? props.ref : dummyRef;
379
+ const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
321
380
  let el;
322
- if ('k-if' in props && !props['k-if']) {
323
- // & make comment placeholder in case that ref might be redrawn later
324
- el = document.createComment('k-if');
325
- ref.value = el;
326
- return el;
327
- }
328
- // Handle function components
329
- if (typeof tag === 'function') {
330
- el = tag(props);
331
- }
332
- else {
333
- el = h(tag, props, props.children);
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
- ref.value = el;
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 };