@ktjs/core 0.21.1 → 0.22.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.
@@ -2,14 +2,8 @@
2
2
  const $isArray = Array.isArray;
3
3
  const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
4
4
 
5
- // Error handling utilities
6
- const $throw = (message) => {
7
- throw new Error('@ktjs/shared: ' + message);
8
- };
9
-
10
5
  // DOM manipulation utilities
11
6
  // # dom natives
12
- const $replaceWith = Element.prototype.replaceWith;
13
7
  /**
14
8
  * & Remove `bind` because it is shockingly slower than wrapper
15
9
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -46,10 +40,84 @@ const $append = // for ie 9/10/11
46
40
  }
47
41
  };
48
42
  const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
43
+ /**
44
+ * Used for `k-model`
45
+ */
46
+ const applyModel = (element, valueRef, propName, eventName) => {
47
+ element[propName] = valueRef.value; // initialize
48
+ valueRef.addOnChange((newValue) => (element[propName] = newValue));
49
+ element.addEventListener(eventName, () => (valueRef.value = element[propName]));
50
+ };
49
51
 
50
52
  // Shared utilities and cached native methods for kt.js framework
51
53
  // Re-export all utilities
52
- Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
54
+ Object.defineProperty(window, '__ktjs__', { value: '0.22.2' });
55
+
56
+ class KTRef {
57
+ /**
58
+ * Indicates that this is a KTRef instance
59
+ */
60
+ isKT = true;
61
+ /**
62
+ * @internal
63
+ */
64
+ _value;
65
+ /**
66
+ * @internal
67
+ */
68
+ _onChanges;
69
+ constructor(_value, _onChanges) {
70
+ this._value = _value;
71
+ this._onChanges = _onChanges;
72
+ }
73
+ /**
74
+ * If new value and old value are both nodes, the old one will be replaced in the DOM
75
+ */
76
+ get value() {
77
+ return this._value;
78
+ }
79
+ set value(newValue) {
80
+ if (newValue === this._value) {
81
+ return;
82
+ }
83
+ // replace the old node with the new one in the DOM if both are nodes
84
+ if (this._value instanceof Node && newValue instanceof Node) {
85
+ if (newValue.contains(this._value)) {
86
+ this._value.remove();
87
+ }
88
+ this._value.replaceWith(newValue);
89
+ }
90
+ const oldValue = this._value;
91
+ this._value = newValue;
92
+ for (let i = 0; i < this._onChanges.length; i++) {
93
+ this._onChanges[i](newValue, oldValue);
94
+ }
95
+ }
96
+ addOnChange(callback) {
97
+ this._onChanges.push(callback);
98
+ }
99
+ removeOnChange(callback) {
100
+ for (let i = this._onChanges.length - 1; i >= 0; i--) {
101
+ if (this._onChanges[i] === callback) {
102
+ this._onChanges.splice(i, 1);
103
+ return true;
104
+ }
105
+ }
106
+ return false;
107
+ }
108
+ }
109
+ const isKTRef = (obj) => {
110
+ return typeof obj === 'object' && obj !== null && obj.isKT === true;
111
+ };
112
+ /**
113
+ * Reference to the created HTML element.
114
+ * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
115
+ * - can alse be used to store normal values, but it is not reactive.
116
+ * @param value mostly an HTMLElement
117
+ */
118
+ function ref(value, onChange) {
119
+ return new KTRef(value, []);
120
+ }
53
121
 
54
122
  const booleanHandler = (element, key, value) => {
55
123
  if (key in element) {
@@ -115,6 +183,7 @@ function attrIsObject(element, attr) {
115
183
  key === 'style' ||
116
184
  key === 'children' ||
117
185
  key === 'k-if' ||
186
+ key.startsWith('k-model') ||
118
187
  key === 'ref') {
119
188
  continue;
120
189
  }
@@ -137,7 +206,7 @@ function applyAttr(element, attr) {
137
206
  attrIsObject(element, attr);
138
207
  }
139
208
  else {
140
- throw new Error('kt.js: attr must be an object.');
209
+ throw new Error('[kt.js error] attr must be an object.');
141
210
  }
142
211
  }
143
212
 
@@ -192,6 +261,30 @@ function applyContent(element, content) {
192
261
  }
193
262
  }
194
263
 
264
+ function applyKModel(element, valueRef) {
265
+ if (!isKTRef(valueRef)) {
266
+ console.warn('[kt.js warn] k-model value must be a KTRef.');
267
+ return;
268
+ }
269
+ if (element instanceof HTMLInputElement) {
270
+ if (element.type === 'radio' || element.type === 'checkbox') {
271
+ applyModel(element, valueRef, 'checked', 'change');
272
+ }
273
+ else {
274
+ applyModel(element, valueRef, 'value', 'input');
275
+ }
276
+ }
277
+ else if (element instanceof HTMLSelectElement) {
278
+ applyModel(element, valueRef, 'value', 'change');
279
+ }
280
+ else if (element instanceof HTMLTextAreaElement) {
281
+ applyModel(element, valueRef, 'value', 'input');
282
+ }
283
+ else {
284
+ console.warn('[kt.js warn] not supported element for k-model:');
285
+ }
286
+ }
287
+
195
288
  const htmlCreator = (tag) => document.createElement(tag);
196
289
  const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
197
290
  const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
@@ -209,7 +302,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
209
302
  * ## About
210
303
  * @package @ktjs/core
211
304
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
212
- * @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
305
+ * @version 0.22.2 (Last Update: 2026.02.02 20:28:37.901)
213
306
  * @license MIT
214
307
  * @link https://github.com/baendlorel/kt.js
215
308
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -218,7 +311,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
218
311
  */
219
312
  const h = (tag, attr, content) => {
220
313
  if (typeof tag !== 'string') {
221
- $throw('tagName must be a string.');
314
+ throw new Error('[kt.js error] tagName must be a string.');
222
315
  }
223
316
  if (attr) {
224
317
  if (SVG_ATTR_FLAG in attr) {
@@ -238,74 +331,17 @@ const h = (tag, attr, content) => {
238
331
  // * Handle content
239
332
  applyAttr(element, attr);
240
333
  applyContent(element, content);
241
- return element;
242
- };
243
-
244
- class KTRef {
245
- /**
246
- * Indicates that this is a KTRef instance
247
- */
248
- isKT = true;
249
- /**
250
- * @internal
251
- */
252
- _value;
253
- /**
254
- * @internal
255
- */
256
- _onChanges;
257
- constructor(_value, _onChanges) {
258
- this._value = _value;
259
- this._onChanges = _onChanges;
260
- }
261
- /**
262
- * If new value and old value are both nodes, the old one will be replaced in the DOM
263
- */
264
- get value() {
265
- return this._value;
266
- }
267
- set value(newValue) {
268
- if (newValue === this._value) {
269
- return;
334
+ if (typeof attr === 'object' && attr !== null && 'k-model' in attr) {
335
+ const kmodel = attr['k-model'];
336
+ if (isKTRef(kmodel)) {
337
+ applyKModel(element, kmodel);
270
338
  }
271
- // replace the old node with the new one in the DOM if both are nodes
272
- if (this._value instanceof Node && newValue instanceof Node) {
273
- if (newValue.contains(this._value)) {
274
- this._value.remove();
275
- }
276
- this._value.replaceWith(newValue);
277
- }
278
- const oldValue = this._value;
279
- this._value = newValue;
280
- for (let i = 0; i < this._onChanges.length; i++) {
281
- this._onChanges[i](newValue, oldValue);
282
- }
283
- }
284
- addOnChange(callback) {
285
- this._onChanges.push(callback);
286
- }
287
- removeOnChange(callback) {
288
- for (let i = this._onChanges.length - 1; i >= 0; i--) {
289
- if (this._onChanges[i] === callback) {
290
- this._onChanges.splice(i, 1);
291
- return true;
292
- }
339
+ else {
340
+ throw new Error('[kt.js error] k-model value must be a KTRef.');
293
341
  }
294
- return false;
295
342
  }
296
- }
297
- const isKTRef = (obj) => {
298
- return typeof obj === 'object' && obj !== null && obj.isKT === true;
343
+ return element;
299
344
  };
300
- /**
301
- * Reference to the created HTML element.
302
- * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
303
- * - can alse be used to store normal values, but it is not reactive.
304
- * @param value mostly an HTMLElement
305
- */
306
- function ref(value, onChange) {
307
- return new KTRef(value, []);
308
- }
309
345
 
310
346
  const dummyRef = { value: null };
311
347
  const create = (tag, props) => {
@@ -335,7 +371,7 @@ function jsx(tag, props) {
335
371
  }
336
372
  const oldEl = el;
337
373
  el = newValue ? create(tag, props) : placeholder();
338
- $replaceWith.call(oldEl, el);
374
+ oldEl.replaceWith(el);
339
375
  maybeDummyRef.value = el;
340
376
  });
341
377
  condition = kif.value;
@@ -356,7 +392,7 @@ function jsx(tag, props) {
356
392
  * Note: kt.js doesn't have a real Fragment concept,
357
393
  */
358
394
  function Fragment(_props) {
359
- throw new Error("kt.js doesn't have a Fragment concept");
395
+ throw new Error("[kt.js error] doesn't have a Fragment concept");
360
396
  // const { children } = props ?? {};
361
397
  // if (!children) {
362
398
  // return ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.21.1",
3
+ "version": "0.22.2",
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.2"
47
+ "@ktjs/shared": "0.22.2"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "rollup -c rollup.config.mjs",