@ktjs/core 0.12.0 → 0.13.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,16 +2,6 @@ const $throw = (message) => {
2
2
  throw new Error('kt.js: ' + message);
3
3
  };
4
4
 
5
- const $isArray = Array.isArray;
6
- const $keys = Object.keys;
7
- const $defines = Object.defineProperties;
8
- const $mark = (func, tag) => $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
9
- const emptyPromiseHandler = () => ({});
10
- if (typeof Promise === 'undefined') {
11
- window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
12
- }
13
- const $isThenable = (o) => typeof o === 'object' && o !== null && 'then' in o && typeof o.then === 'function';
14
-
15
5
  /**
16
6
  * & Remove `bind` because it is shockingly slower than wrapper
17
7
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -50,22 +40,30 @@ const $append = // for ie 9/10/11
50
40
  }
51
41
  };
52
42
 
53
- function booleanHandler(element, key, value) {
43
+ const $isArray = Array.isArray;
44
+ const $keys = Object.keys;
45
+ const emptyPromiseHandler = () => ({});
46
+ if (typeof Promise === 'undefined') {
47
+ window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
48
+ }
49
+ const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
50
+
51
+ const booleanHandler = (element, key, value) => {
54
52
  if (key in element) {
55
53
  element[key] = !!value;
56
54
  }
57
55
  else {
58
56
  element.setAttribute(key, value);
59
57
  }
60
- }
61
- function valueHandler(element, key, value) {
58
+ };
59
+ const valueHandler = (element, key, value) => {
62
60
  if (key in element) {
63
61
  element[key] = value;
64
62
  }
65
63
  else {
66
64
  element.setAttribute(key, value);
67
65
  }
68
- }
66
+ };
69
67
  // Attribute handlers map for optimized lookup
70
68
  const handlers = {
71
69
  checked: booleanHandler,
@@ -88,13 +86,18 @@ const handlers = {
88
86
  muted: booleanHandler,
89
87
  defer: booleanHandler,
90
88
  async: booleanHandler,
91
- hidden: function (element, _key, value) {
92
- element.hidden = !!value;
93
- },
89
+ hidden: (element, _key, value) => (element.hidden = !!value),
94
90
  };
95
- const defaultHandler = function (element, key, value) {
96
- return element.setAttribute(key, value);
91
+ const ktEventHandlers = {
92
+ 'on:ktchange': (element, handler) => element.addEventListener('change', () => handler(element.value)),
93
+ 'ontrim:ktchange': (element, handler) => element.addEventListener('change', () => handler(element.value.trim())),
94
+ 'on:ktchangenumber': (element, handler) => element.addEventListener('change', () => handler(Number(element.value))),
95
+ 'on:ktinput': (element, handler) => element.addEventListener('input', () => handler(element.value)),
96
+ 'ontrim:ktinput': (element, handler) => element.addEventListener('input', () => handler(element.value.trim())),
97
+ 'on:ktinputnumber': (element, handler) => element.addEventListener('input', () => handler(Number(element.value))),
97
98
  };
99
+
100
+ const defaultHandler = (element, key, value) => element.setAttribute(key, value);
98
101
  function attrIsObject(element, attr) {
99
102
  const classValue = attr.class;
100
103
  const style = attr.style;
@@ -114,11 +117,19 @@ function attrIsObject(element, attr) {
114
117
  delete attr.style;
115
118
  }
116
119
  const keys = $keys(attr);
120
+ // todo 这里的处理每次遍历都要if所有的情况,能否用map或者对象来优化?
117
121
  for (let i = keys.length - 1; i >= 0; i--) {
118
122
  const key = keys[i];
119
123
  const o = attr[key];
120
124
  // force register on:xxx as an event handler
121
125
  // !if o is not valid, the throwing job will be done by `on`, not kt.js
126
+ // # special handling for kt.js specific events
127
+ const ktEvent = ktEventHandlers[key];
128
+ if (ktEvent) {
129
+ ktEvent(element, o);
130
+ continue;
131
+ }
132
+ // # normal event handler
122
133
  if (key.startsWith('on:')) {
123
134
  element.addEventListener(key.slice(3), o); // chop off the `@`
124
135
  continue;
@@ -205,7 +216,7 @@ function applyContent(element, content) {
205
216
  * ## About
206
217
  * @package @ktjs/core
207
218
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
208
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
219
+ * @version 0.13.2 (Last Update: 2026.01.16 19:38:40.621)
209
220
  * @license MIT
210
221
  * @link https://github.com/baendlorel/kt.js
211
222
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -223,45 +234,67 @@ const h = ((tag, attr = '', content = '') => {
223
234
  applyContent(element, content);
224
235
  return element;
225
236
  });
226
- $mark(h, 'h');
227
237
 
228
238
  /**
229
239
  * @param tag html tag or function component
230
240
  * @param props properties/attributes
231
- * @param _metadata metadata is ignored
232
241
  */
233
- function jsx(tag, props, ..._metadata) {
242
+ function jsx(tag, props = {}) {
243
+ const ref = props.ref?.isKT ? props.ref : null;
244
+ if (ref) {
245
+ delete props.ref;
246
+ }
234
247
  // Handle function components
235
248
  if (typeof tag === 'function') {
236
- const propObj = typeof props === 'string' ? { class: props } : props || {};
237
- const children = propObj.children;
238
- return tag({ ...propObj, children });
239
- }
240
- // Handle regular HTML tags
241
- const propObj = typeof props === 'string' ? { class: props } : props;
242
- if (propObj === undefined || propObj === null) {
243
- return h(tag);
244
- }
245
- const children = propObj.children;
246
- delete propObj.children;
247
- // deal with ref attribute
248
- const ref = propObj.ref?.isKT ? propObj.ref : null;
249
- if (ref) {
250
- delete propObj.ref;
249
+ let el = tag(props);
250
+ if (!el.redraw) {
251
+ el.redraw = (newProps) => {
252
+ props = newProps ? { ...props, ...newProps } : props;
253
+ // $ same as below
254
+ const old = el;
255
+ el = tag(props);
256
+ el.redraw = old.redraw; // inherit redraw
257
+ if (ref) {
258
+ ref.value = el;
259
+ }
260
+ old.replaceWith(el);
261
+ };
262
+ }
263
+ if (ref) {
264
+ ref.value = el;
265
+ }
266
+ return el;
251
267
  }
252
- const el = h(tag, propObj, children);
253
- if (ref) {
254
- ref.value = el;
268
+ else {
269
+ // & deal children here
270
+ let children = props.children;
271
+ delete props.children;
272
+ let el = h(tag, props, children);
273
+ if (ref) {
274
+ ref.value = el;
275
+ }
276
+ el.redraw = (newProps, newChildren) => {
277
+ props = newProps ? { ...props, ...newProps } : props;
278
+ children = (newChildren ?? children);
279
+ // $ same as above
280
+ const old = el;
281
+ el = h(tag, props, children);
282
+ el.redraw = old.redraw; // inherit redraw
283
+ if (ref) {
284
+ ref.value = el;
285
+ }
286
+ old.replaceWith(el);
287
+ };
288
+ return el;
255
289
  }
256
- return el;
257
290
  }
258
291
  /**
259
292
  * Fragment support - returns an array of children
260
293
  * Note: kt.js doesn't have a real Fragment concept,
261
294
  */
262
295
  function Fragment(props) {
263
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
264
- // const { children } = props || {};
296
+ throw new Error("kt.js doesn't have a Fragment concept");
297
+ // const { children } = props ?? {};
265
298
  // if (!children) {
266
299
  // return ;
267
300
  // }
@@ -10,6 +10,33 @@ interface KTRef<T> {
10
10
  isKT: true;
11
11
  }
12
12
 
13
+ type KTHTMLElement = HTMLElement & {
14
+ /**
15
+ * Automically generate a redraw function if it is not provided
16
+ * @param props
17
+ */
18
+ redraw: (props?: KTAttribute, children?: KTRawContent) => void;
19
+ };
20
+
21
+ declare global {
22
+ namespace JSX {
23
+ type Element = KTHTMLElement;
24
+
25
+ interface IntrinsicElements {
26
+ [tag: string]: KTAttribute & { children?: KTRawContent };
27
+ }
28
+
29
+ // interface IntrinsicAttributes {
30
+ // key?: string | number;
31
+ // }
32
+ type IntrinsicAttributes = KTAttribute;
33
+
34
+ interface ElementChildrenAttribute {
35
+ children: {};
36
+ }
37
+ }
38
+ }
39
+
13
40
  type KTAvailableContent =
14
41
  | KTRef<any>
15
42
  | HTMLElement
@@ -86,7 +113,17 @@ type KTPrefixedEventHandlers = {
86
113
  [EventName in keyof HTMLElementEventMap as `on:${EventName}`]?: (ev: HTMLElementEventMap[EventName]) => void;
87
114
  };
88
115
 
89
- type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
116
+ type KTSpecialEventHandlers = {
117
+ 'on:ktchange'?: (value: string) => void;
118
+ 'ontrim:ktchange'?: (value: string) => void;
119
+ 'on:ktchangenumber'?: (value: number) => void;
120
+
121
+ 'on:ktinput'?: (value: string) => void;
122
+ 'ontrim:ktinput'?: (value: string) => void;
123
+ 'on:ktinputnumber'?: (value: number) => void;
124
+ };
125
+
126
+ type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers & KTSpecialEventHandlers;
90
127
 
91
128
  type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagNameMap[T] : HTMLElement;
92
129
  type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent) => HTML<T>) & {
@@ -103,7 +140,7 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
103
140
  * ## About
104
141
  * @package @ktjs/core
105
142
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
106
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
143
+ * @version 0.13.2 (Last Update: 2026.01.16 19:38:40.621)
107
144
  * @license MIT
108
145
  * @link https://github.com/baendlorel/kt.js
109
146
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -112,12 +149,12 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
112
149
  */
113
150
  declare const h: H;
114
151
 
152
+ type JSXTag = HTMLTag | ((props?: any) => HTMLElement) | ((props?: any) => Promise<HTMLElement>) | ((props?: any) => KTHTMLElement) | ((props?: any) => Promise<KTHTMLElement>);
115
153
  /**
116
154
  * @param tag html tag or function component
117
155
  * @param props properties/attributes
118
- * @param _metadata metadata is ignored
119
156
  */
120
- declare function jsx<T extends HTMLTag>(tag: T | Function, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T] | HTMLElement;
157
+ declare function jsx(tag: JSXTag, props?: KTAttribute): KTHTMLElement;
121
158
  /**
122
159
  * Fragment support - returns an array of children
123
160
  * Note: kt.js doesn't have a real Fragment concept,
@@ -2,16 +2,6 @@ const $throw = (message) => {
2
2
  throw new Error('kt.js: ' + message);
3
3
  };
4
4
 
5
- const $isArray = Array.isArray;
6
- const $keys = Object.keys;
7
- const $defines = Object.defineProperties;
8
- const $mark = (func, tag) => $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
9
- const emptyPromiseHandler = () => ({});
10
- if (typeof Promise === 'undefined') {
11
- window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
12
- }
13
- const $isThenable = (o) => typeof o === 'object' && o !== null && 'then' in o && typeof o.then === 'function';
14
-
15
5
  /**
16
6
  * & Remove `bind` because it is shockingly slower than wrapper
17
7
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -50,22 +40,30 @@ const $append = // for ie 9/10/11
50
40
  }
51
41
  };
52
42
 
53
- function booleanHandler(element, key, value) {
43
+ const $isArray = Array.isArray;
44
+ const $keys = Object.keys;
45
+ const emptyPromiseHandler = () => ({});
46
+ if (typeof Promise === 'undefined') {
47
+ window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
48
+ }
49
+ const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
50
+
51
+ const booleanHandler = (element, key, value) => {
54
52
  if (key in element) {
55
53
  element[key] = !!value;
56
54
  }
57
55
  else {
58
56
  element.setAttribute(key, value);
59
57
  }
60
- }
61
- function valueHandler(element, key, value) {
58
+ };
59
+ const valueHandler = (element, key, value) => {
62
60
  if (key in element) {
63
61
  element[key] = value;
64
62
  }
65
63
  else {
66
64
  element.setAttribute(key, value);
67
65
  }
68
- }
66
+ };
69
67
  // Attribute handlers map for optimized lookup
70
68
  const handlers = {
71
69
  checked: booleanHandler,
@@ -88,13 +86,18 @@ const handlers = {
88
86
  muted: booleanHandler,
89
87
  defer: booleanHandler,
90
88
  async: booleanHandler,
91
- hidden: function (element, _key, value) {
92
- element.hidden = !!value;
93
- },
89
+ hidden: (element, _key, value) => (element.hidden = !!value),
94
90
  };
95
- const defaultHandler = function (element, key, value) {
96
- return element.setAttribute(key, value);
91
+ const ktEventHandlers = {
92
+ 'on:ktchange': (element, handler) => element.addEventListener('change', () => handler(element.value)),
93
+ 'ontrim:ktchange': (element, handler) => element.addEventListener('change', () => handler(element.value.trim())),
94
+ 'on:ktchangenumber': (element, handler) => element.addEventListener('change', () => handler(Number(element.value))),
95
+ 'on:ktinput': (element, handler) => element.addEventListener('input', () => handler(element.value)),
96
+ 'ontrim:ktinput': (element, handler) => element.addEventListener('input', () => handler(element.value.trim())),
97
+ 'on:ktinputnumber': (element, handler) => element.addEventListener('input', () => handler(Number(element.value))),
97
98
  };
99
+
100
+ const defaultHandler = (element, key, value) => element.setAttribute(key, value);
98
101
  function attrIsObject(element, attr) {
99
102
  const classValue = attr.class;
100
103
  const style = attr.style;
@@ -114,11 +117,19 @@ function attrIsObject(element, attr) {
114
117
  delete attr.style;
115
118
  }
116
119
  const keys = $keys(attr);
120
+ // todo 这里的处理每次遍历都要if所有的情况,能否用map或者对象来优化?
117
121
  for (let i = keys.length - 1; i >= 0; i--) {
118
122
  const key = keys[i];
119
123
  const o = attr[key];
120
124
  // force register on:xxx as an event handler
121
125
  // !if o is not valid, the throwing job will be done by `on`, not kt.js
126
+ // # special handling for kt.js specific events
127
+ const ktEvent = ktEventHandlers[key];
128
+ if (ktEvent) {
129
+ ktEvent(element, o);
130
+ continue;
131
+ }
132
+ // # normal event handler
122
133
  if (key.startsWith('on:')) {
123
134
  element.addEventListener(key.slice(3), o); // chop off the `@`
124
135
  continue;
@@ -205,7 +216,7 @@ function applyContent(element, content) {
205
216
  * ## About
206
217
  * @package @ktjs/core
207
218
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
208
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
219
+ * @version 0.13.2 (Last Update: 2026.01.16 19:38:40.621)
209
220
  * @license MIT
210
221
  * @link https://github.com/baendlorel/kt.js
211
222
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -223,45 +234,67 @@ const h = ((tag, attr = '', content = '') => {
223
234
  applyContent(element, content);
224
235
  return element;
225
236
  });
226
- $mark(h, 'h');
227
237
 
228
238
  /**
229
239
  * @param tag html tag or function component
230
240
  * @param props properties/attributes
231
- * @param _metadata metadata is ignored
232
241
  */
233
- function jsx(tag, props, ..._metadata) {
242
+ function jsx(tag, props = {}) {
243
+ const ref = props.ref?.isKT ? props.ref : null;
244
+ if (ref) {
245
+ delete props.ref;
246
+ }
234
247
  // Handle function components
235
248
  if (typeof tag === 'function') {
236
- const propObj = typeof props === 'string' ? { class: props } : props || {};
237
- const children = propObj.children;
238
- return tag({ ...propObj, children });
239
- }
240
- // Handle regular HTML tags
241
- const propObj = typeof props === 'string' ? { class: props } : props;
242
- if (propObj === undefined || propObj === null) {
243
- return h(tag);
244
- }
245
- const children = propObj.children;
246
- delete propObj.children;
247
- // deal with ref attribute
248
- const ref = propObj.ref?.isKT ? propObj.ref : null;
249
- if (ref) {
250
- delete propObj.ref;
249
+ let el = tag(props);
250
+ if (!el.redraw) {
251
+ el.redraw = (newProps) => {
252
+ props = newProps ? { ...props, ...newProps } : props;
253
+ // $ same as below
254
+ const old = el;
255
+ el = tag(props);
256
+ el.redraw = old.redraw; // inherit redraw
257
+ if (ref) {
258
+ ref.value = el;
259
+ }
260
+ old.replaceWith(el);
261
+ };
262
+ }
263
+ if (ref) {
264
+ ref.value = el;
265
+ }
266
+ return el;
251
267
  }
252
- const el = h(tag, propObj, children);
253
- if (ref) {
254
- ref.value = el;
268
+ else {
269
+ // & deal children here
270
+ let children = props.children;
271
+ delete props.children;
272
+ let el = h(tag, props, children);
273
+ if (ref) {
274
+ ref.value = el;
275
+ }
276
+ el.redraw = (newProps, newChildren) => {
277
+ props = newProps ? { ...props, ...newProps } : props;
278
+ children = (newChildren ?? children);
279
+ // $ same as above
280
+ const old = el;
281
+ el = h(tag, props, children);
282
+ el.redraw = old.redraw; // inherit redraw
283
+ if (ref) {
284
+ ref.value = el;
285
+ }
286
+ old.replaceWith(el);
287
+ };
288
+ return el;
255
289
  }
256
- return el;
257
290
  }
258
291
  /**
259
292
  * Fragment support - returns an array of children
260
293
  * Note: kt.js doesn't have a real Fragment concept,
261
294
  */
262
295
  function Fragment(props) {
263
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
264
- // const { children } = props || {};
296
+ throw new Error("kt.js doesn't have a Fragment concept");
297
+ // const { children } = props ?? {};
265
298
  // if (!children) {
266
299
  // return ;
267
300
  // }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.12.0",
3
+ "version": "0.13.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",