@ktjs/core 0.12.0 → 0.13.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 CHANGED
@@ -2,26 +2,39 @@
2
2
 
3
3
  <img src="https://raw.githubusercontent.com/baendlorel/kt.js/dev/.assets/ktjs-0.0.1.svg" alt="KT.js Logo" width="150"/>
4
4
 
5
- > 📦 Part of [KT.js](https://raw.githubusercontent.com/baendlorel/kt.js/dev/README.md) - A simple and easy-to-use web framework that never re-renders.
5
+ [![npm version](https://img.shields.io/npm/v/@ktjs/core.svg)](https://www.npmjs.com/package/@ktjs/core)
6
6
 
7
- Core DOM manipulation utilities for KT.js framework.
7
+ > 📦 Part of [KT.js](https://github.com/baendlorel/kt.js) - A simple and easy-to-use web framework that never re-renders.
8
+
9
+ Core DOM manipulation utilities for KT.js framework with built-in JSX/TSX support.
8
10
 
9
11
  ## Overview
10
12
 
11
13
  `@ktjs/core` is the foundation of KT.js, providing the essential `h` function and DOM utilities for building web applications with direct DOM manipulation. It emphasizes performance, type safety, and minimal abstraction over native DOM APIs.
12
14
 
15
+ **Current Version:** 0.13.0
16
+
13
17
  ## Features
14
18
 
15
19
  - **`h` Function**: Create HTMLElements with a simple, flexible API
16
20
  - Support for attributes, content, and event handlers
17
- - Special `@<eventName>` syntax for event handlers
21
+ - `on:<eventName>` syntax for event handlers (e.g., `on:click`)
18
22
  - Function attributes automatically treated as event listeners
19
23
  - Full TypeScript support with intelligent type inference
24
+ - **JSX/TSX Support**: Built-in JSX runtime (no separate package needed)
25
+ - Zero virtual DOM - JSX compiles directly to `h()` function calls
26
+ - Full HTML element type inference (`<button>` returns `HTMLButtonElement`)
27
+ - Support for function components
28
+ - **NEW**: `redraw()` method for controlled re-rendering
20
29
  - **KTAsync Component**: Handle async components with ease
21
30
  - Automatic handling of Promise-based components
22
31
  - Seamless integration with JSX/TSX
23
32
  - Fallback placeholder during async loading
24
33
  - Type-safe async component support
34
+ - **Redraw Mechanism**: Fine-grained control over component updates
35
+ - Update props and children selectively
36
+ - Efficient replacement strategy
37
+ - Works with both native elements and function components
25
38
  - **DOM Utilities**: Helper functions for common DOM operations
26
39
  - Native method caching for performance
27
40
  - Symbol-based private properties for internal state
@@ -68,20 +81,20 @@ const card = h('div', { class: 'card' }, [
68
81
  ```typescript
69
82
  import { h } from '@ktjs/core';
70
83
 
71
- // Function attribute (treated as event listener)
84
+ // on: prefixed attribute (event handler)
72
85
  const button1 = h(
73
86
  'button',
74
87
  {
75
- click: () => alert('Clicked!'),
88
+ 'on:click': () => alert('Clicked!'),
76
89
  },
77
90
  'Button 1'
78
91
  );
79
92
 
80
- // @-prefixed attribute (explicitly an event handler)
93
+ // Function attribute (also treated as event listener)
81
94
  const button2 = h(
82
95
  'button',
83
96
  {
84
- '@click': (e) => console.log('Event:', e),
97
+ click: (e) => console.log('Event:', e),
85
98
  'data-id': '123', // Regular attribute
86
99
  },
87
100
  'Button 2'
@@ -89,18 +102,75 @@ const button2 = h(
89
102
 
90
103
  // Both regular and event handler for same name
91
104
  const input = h('input', {
92
- change: 'change-value', // Regular attribute
93
- '@change': (e) => console.log('Changed'), // Event listener
105
+ value: 'initial', // Regular attribute
106
+ 'on:change': (e) => console.log('Changed'), // Event listener
94
107
  });
95
108
  ```
96
109
 
110
+ ### JSX/TSX Support
111
+
112
+ ```tsx
113
+ import { h } from '@ktjs/core';
114
+
115
+ // Configure tsconfig.json
116
+ {
117
+ "compilerOptions": {
118
+ "jsx": "react-jsx",
119
+ "jsxImportSource": "@ktjs/core"
120
+ }
121
+ }
122
+
123
+ // Use JSX syntax
124
+ const App = () => (
125
+ <div class="app">
126
+ <h1>Hello KT.js</h1>
127
+ <button on:click={() => alert('Hi')}>Click me</button>
128
+ </div>
129
+ );
130
+
131
+ // Function components
132
+ const Greeting = ({ name }: { name: string }) => (
133
+ <div class="greeting">Hello, {name}!</div>
134
+ );
135
+
136
+ const app = <Greeting name="World" />;
137
+ ```
138
+
139
+ ### Redraw Mechanism (v0.11+)
140
+
141
+ The new `redraw()` method allows you to update components efficiently:
142
+
143
+ ```tsx
144
+ import { h, KTHTMLElement } from '@ktjs/core';
145
+
146
+ // With JSX - get element with redraw method
147
+ const counter = (<button on:click={() => counter.redraw({ count: count + 1 })}>Count: {0}</button>) as KTHTMLElement;
148
+
149
+ // Function component with redraw
150
+ const Counter = ({ count = 0 }: { count?: number }) => (
151
+ <div>
152
+ <div>Count: {count}</div>
153
+ <button on:click={() => element.redraw({ count: count + 1 })}>Increment</button>
154
+ </div>
155
+ );
156
+
157
+ const element = (<Counter />) as KTHTMLElement;
158
+
159
+ // Update props manually
160
+ element.redraw({ count: 10 });
161
+
162
+ // Update children (for native elements)
163
+ const div = (<div>Old content</div>) as KTHTMLElement;
164
+ div.redraw(undefined, 'New content');
165
+ ```
166
+
97
167
  ### Async Components
98
168
 
99
169
  ```typescript
100
- import { KTAsync } from '@ktjs/core';
170
+ import { KTAsync, h } from '@ktjs/core';
101
171
 
102
172
  // Define an async component that returns a Promise
103
- const AsyncComponent = function () {
173
+ const AsyncComponent = () => {
104
174
  return new Promise<HTMLElement>((resolve) => {
105
175
  setTimeout(() => {
106
176
  const element = h('div', { class: 'loaded' }, 'Content loaded!');
@@ -122,11 +192,21 @@ const App = () => (
122
192
  <KTAsync component={AsyncComponent} />
123
193
  </div>
124
194
  );
195
+
196
+ // With custom placeholder
197
+ const AppWithSkeleton = () => (
198
+ <div>
199
+ <KTAsync
200
+ component={AsyncComponent}
201
+ skeleton={<div class="skeleton">Loading...</div>}
202
+ />
203
+ </div>
204
+ );
125
205
  ```
126
206
 
127
207
  **How it works:**
128
208
 
129
- - `KTAsync` creates a placeholder comment node immediately
209
+ - `KTAsync` creates a placeholder (comment node or custom skeleton) immediately
130
210
  - When the Promise resolves, it automatically replaces the placeholder with the actual element
131
211
  - If the component returns a non-Promise value, it's used directly
132
212
  - No manual DOM manipulation needed - just return a Promise from your component
package/dist/index.d.ts CHANGED
@@ -1,14 +1,3 @@
1
- interface KTRuntime {
2
- throws: (message: string) => never;
3
- defines: <T>(o: T, properties: PropertyDescriptorMap & ThisType<any>) => T;
4
- mark: (func: (...args: any[]) => any, tag: string) => void;
5
- }
6
- declare global {
7
- interface Window {
8
- readonly __ktjs__: KTRuntime;
9
- }
10
- }
11
-
12
1
  type otherstring = string & {};
13
2
 
14
3
  /**
@@ -134,7 +123,7 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
134
123
  * ## About
135
124
  * @package @ktjs/core
136
125
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
137
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
126
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
138
127
  * @license MIT
139
128
  * @link https://github.com/baendlorel/kt.js
140
129
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -143,12 +132,39 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
143
132
  */
144
133
  declare const h: H;
145
134
 
135
+ type KTHTMLElement = HTMLElement & {
136
+ /**
137
+ * Automically generate a redraw function if it is not provided
138
+ * @param props
139
+ */
140
+ redraw: (props?: KTAttribute, children?: KTRawContent) => void;
141
+ };
142
+
143
+ declare global {
144
+ namespace JSX {
145
+ type Element = KTHTMLElement;
146
+
147
+ interface IntrinsicElements {
148
+ [tag: string]: KTAttribute & { children?: KTRawContent };
149
+ }
150
+
151
+ // interface IntrinsicAttributes {
152
+ // key?: string | number;
153
+ // }
154
+ type IntrinsicAttributes = KTAttribute;
155
+
156
+ interface ElementChildrenAttribute {
157
+ children: {};
158
+ }
159
+ }
160
+ }
161
+
162
+ type JSXTag = HTMLTag | ((props?: any) => HTMLElement) | ((props?: any) => Promise<HTMLElement>) | ((props?: any) => KTHTMLElement) | ((props?: any) => Promise<KTHTMLElement>);
146
163
  /**
147
164
  * @param tag html tag or function component
148
165
  * @param props properties/attributes
149
- * @param _metadata metadata is ignored
150
166
  */
151
- declare function jsx<T extends HTMLTag>(tag: T | Function, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T] | HTMLElement;
167
+ declare function jsx(tag: JSXTag, props?: KTAttribute): KTHTMLElement;
152
168
  /**
153
169
  * Fragment support - returns an array of children
154
170
  * Note: kt.js doesn't have a real Fragment concept,
@@ -166,25 +182,6 @@ declare const jsxDEV: typeof jsx;
166
182
  */
167
183
  declare const jsxs: typeof jsx;
168
184
 
169
- declare global {
170
- namespace JSX {
171
- type Element = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
172
-
173
- interface IntrinsicElements {
174
- [tag: string]: KTAttribute & { children?: KTRawContent };
175
- }
176
-
177
- // interface IntrinsicAttributes {
178
- // key?: string | number;
179
- // }
180
- type IntrinsicAttributes = KTAttribute;
181
-
182
- interface ElementChildrenAttribute {
183
- children: {};
184
- }
185
- }
186
- }
187
-
188
185
  /**
189
186
  * Extract component props type (excluding ref and children)
190
187
  */
@@ -197,4 +194,4 @@ declare function KTAsync<T extends KTComponent>(props: {
197
194
  } & ExtractComponentProps<T>): HTMLElement;
198
195
 
199
196
  export { Fragment, KTAsync, h as createElement, h, jsx, jsxDEV, jsxs, ref };
200
- export type { EventHandler, HTMLTag, KTAttribute, KTRawAttr, KTRawContent, KTRawContents, KTRef, KTRuntime };
197
+ export type { EventHandler, HTMLTag, KTAttribute, KTHTMLElement, KTRawAttr, KTRawContent, KTRawContents, KTRef };
@@ -5,33 +5,6 @@ var __ktjs_core__ = (function (exports) {
5
5
  throw new Error('kt.js: ' + message);
6
6
  };
7
7
 
8
- const $isArray = Array.isArray;
9
- const $keys = Object.keys;
10
- const $defines = Object.defineProperties;
11
- const $mark = (func, tag) => $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
12
- const emptyPromiseHandler = () => ({});
13
- if (typeof Promise === 'undefined') {
14
- window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
15
- }
16
- const $isThenable = (o) => typeof o === 'object' && o !== null && 'then' in o && typeof o.then === 'function';
17
-
18
- (() => {
19
- const runtimeKey = '__ktjs__';
20
- if (runtimeKey in window) {
21
- return;
22
- }
23
- const __ktjs__ = Object.create(null);
24
- // & We can add new functions when we need more
25
- const descriptor = {
26
- throws: { value: $throw, enumerable: true },
27
- defines: { value: $defines, enumerable: true },
28
- mark: { value: $mark, enumerable: true },
29
- };
30
- $defines(__ktjs__, descriptor);
31
- $defines(window, { [runtimeKey]: { value: __ktjs__, enumerable: true } });
32
- return {};
33
- })();
34
-
35
8
  /**
36
9
  * & Remove `bind` because it is shockingly slower than wrapper
37
10
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -70,6 +43,14 @@ var __ktjs_core__ = (function (exports) {
70
43
  }
71
44
  };
72
45
 
46
+ const $isArray = Array.isArray;
47
+ const $keys = Object.keys;
48
+ const emptyPromiseHandler = () => ({});
49
+ if (typeof Promise === 'undefined') {
50
+ window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
51
+ }
52
+ const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
53
+
73
54
  function booleanHandler(element, key, value) {
74
55
  if (key in element) {
75
56
  element[key] = !!value;
@@ -225,7 +206,7 @@ var __ktjs_core__ = (function (exports) {
225
206
  * ## About
226
207
  * @package @ktjs/core
227
208
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
228
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
209
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
229
210
  * @license MIT
230
211
  * @link https://github.com/baendlorel/kt.js
231
212
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -243,45 +224,67 @@ var __ktjs_core__ = (function (exports) {
243
224
  applyContent(element, content);
244
225
  return element;
245
226
  });
246
- $mark(h, 'h');
247
227
 
248
228
  /**
249
229
  * @param tag html tag or function component
250
230
  * @param props properties/attributes
251
- * @param _metadata metadata is ignored
252
231
  */
253
- function jsx(tag, props, ..._metadata) {
232
+ function jsx(tag, props = {}) {
233
+ const ref = props.ref?.isKT ? props.ref : null;
234
+ if (ref) {
235
+ delete props.ref;
236
+ }
254
237
  // Handle function components
255
238
  if (typeof tag === 'function') {
256
- const propObj = typeof props === 'string' ? { class: props } : props || {};
257
- const children = propObj.children;
258
- return tag({ ...propObj, children });
259
- }
260
- // Handle regular HTML tags
261
- const propObj = typeof props === 'string' ? { class: props } : props;
262
- if (propObj === undefined || propObj === null) {
263
- return h(tag);
264
- }
265
- const children = propObj.children;
266
- delete propObj.children;
267
- // deal with ref attribute
268
- const ref = propObj.ref?.isKT ? propObj.ref : null;
269
- if (ref) {
270
- delete propObj.ref;
239
+ let el = tag(props);
240
+ if (!el.redraw) {
241
+ el.redraw = (newProps) => {
242
+ props = newProps ? { ...props, ...newProps } : props;
243
+ // $ same as below
244
+ const old = el;
245
+ el = tag(props);
246
+ el.redraw = old.redraw; // inherit redraw
247
+ if (ref) {
248
+ ref.value = el;
249
+ }
250
+ old.replaceWith(el);
251
+ };
252
+ }
253
+ if (ref) {
254
+ ref.value = el;
255
+ }
256
+ return el;
271
257
  }
272
- const el = h(tag, propObj, children);
273
- if (ref) {
274
- ref.value = el;
258
+ else {
259
+ // & deal children here
260
+ let children = props.children;
261
+ delete props.children;
262
+ let el = h(tag, props, children);
263
+ if (ref) {
264
+ ref.value = el;
265
+ }
266
+ el.redraw = (newProps, newChildren) => {
267
+ props = newProps ? { ...props, ...newProps } : props;
268
+ children = (newChildren ?? children);
269
+ // $ same as above
270
+ const old = el;
271
+ el = h(tag, props, children);
272
+ el.redraw = old.redraw; // inherit redraw
273
+ if (ref) {
274
+ ref.value = el;
275
+ }
276
+ old.replaceWith(el);
277
+ };
278
+ return el;
275
279
  }
276
- return el;
277
280
  }
278
281
  /**
279
282
  * Fragment support - returns an array of children
280
283
  * Note: kt.js doesn't have a real Fragment concept,
281
284
  */
282
285
  function Fragment(props) {
283
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
284
- // const { children } = props || {};
286
+ throw new Error("kt.js doesn't have a Fragment concept");
287
+ // const { children } = props ?? {};
285
288
  // if (!children) {
286
289
  // return ;
287
290
  // }
@@ -5,38 +5,6 @@ var __ktjs_core__ = (function (exports) {
5
5
  throw new Error('kt.js: ' + message);
6
6
  };
7
7
 
8
- var $isArray = Array.isArray;
9
- var $keys = Object.keys;
10
- var $defines = Object.defineProperties;
11
- var $mark = function (func, tag) {
12
- return $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
13
- };
14
- var emptyPromiseHandler = function () { return ({}); };
15
- if (typeof Promise === 'undefined') {
16
- window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
17
- }
18
- var $isThenable = function (o) {
19
- return typeof o === 'object' && o !== null && 'then' in o && typeof o.then === 'function';
20
- };
21
-
22
- ((function () {
23
- var _a;
24
- var runtimeKey = '__ktjs__';
25
- if (runtimeKey in window) {
26
- return;
27
- }
28
- var __ktjs__ = Object.create(null);
29
- // & We can add new functions when we need more
30
- var descriptor = {
31
- throws: { value: $throw, enumerable: true },
32
- defines: { value: $defines, enumerable: true },
33
- mark: { value: $mark, enumerable: true },
34
- };
35
- $defines(__ktjs__, descriptor);
36
- $defines(window, (_a = {}, _a[runtimeKey] = { value: __ktjs__, enumerable: true }, _a));
37
- return {};
38
- }))();
39
-
40
8
  /**
41
9
  * & Remove `bind` because it is shockingly slower than wrapper
42
10
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -83,6 +51,16 @@ var __ktjs_core__ = (function (exports) {
83
51
  }
84
52
  };
85
53
 
54
+ var $isArray = Array.isArray;
55
+ var $keys = Object.keys;
56
+ var emptyPromiseHandler = function () { return ({}); };
57
+ if (typeof Promise === 'undefined') {
58
+ window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
59
+ }
60
+ var $isThenable = function (o) {
61
+ return typeof o === 'object' && o !== null && typeof o.then === 'function';
62
+ };
63
+
86
64
  function booleanHandler(element, key, value) {
87
65
  if (key in element) {
88
66
  element[key] = !!value;
@@ -241,7 +219,7 @@ var __ktjs_core__ = (function (exports) {
241
219
  * ## About
242
220
  * @package @ktjs/core
243
221
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
244
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
222
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
245
223
  * @license MIT
246
224
  * @link https://github.com/baendlorel/kt.js
247
225
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -261,7 +239,6 @@ var __ktjs_core__ = (function (exports) {
261
239
  applyContent(element, content);
262
240
  return element;
263
241
  });
264
- $mark(h, 'h');
265
242
 
266
243
  /******************************************************************************
267
244
  Copyright (c) Microsoft Corporation.
@@ -299,41 +276,65 @@ var __ktjs_core__ = (function (exports) {
299
276
  /**
300
277
  * @param tag html tag or function component
301
278
  * @param props properties/attributes
302
- * @param _metadata metadata is ignored
303
279
  */
304
280
  function jsx(tag, props) {
305
281
  var _a;
282
+ if (props === void 0) { props = {}; }
283
+ var ref = ((_a = props.ref) === null || _a === void 0 ? void 0 : _a.isKT) ? props.ref : null;
284
+ if (ref) {
285
+ delete props.ref;
286
+ }
306
287
  // Handle function components
307
288
  if (typeof tag === 'function') {
308
- var propObj_1 = typeof props === 'string' ? { class: props } : props || {};
309
- var children_1 = propObj_1.children;
310
- return tag(__assign(__assign({}, propObj_1), { children: children_1 }));
311
- }
312
- // Handle regular HTML tags
313
- var propObj = typeof props === 'string' ? { class: props } : props;
314
- if (propObj === undefined || propObj === null) {
315
- return h(tag);
316
- }
317
- var children = propObj.children;
318
- delete propObj.children;
319
- // deal with ref attribute
320
- var ref = ((_a = propObj.ref) === null || _a === void 0 ? void 0 : _a.isKT) ? propObj.ref : null;
321
- if (ref) {
322
- delete propObj.ref;
289
+ var el_1 = tag(props);
290
+ if (!el_1.redraw) {
291
+ el_1.redraw = function (newProps) {
292
+ props = newProps ? __assign(__assign({}, props), newProps) : props;
293
+ // $ same as below
294
+ var old = el_1;
295
+ el_1 = tag(props);
296
+ el_1.redraw = old.redraw; // inherit redraw
297
+ if (ref) {
298
+ ref.value = el_1;
299
+ }
300
+ old.replaceWith(el_1);
301
+ };
302
+ }
303
+ if (ref) {
304
+ ref.value = el_1;
305
+ }
306
+ return el_1;
323
307
  }
324
- var el = h(tag, propObj, children);
325
- if (ref) {
326
- ref.value = el;
308
+ else {
309
+ // & deal children here
310
+ var children_1 = props.children;
311
+ delete props.children;
312
+ var el_2 = h(tag, props, children_1);
313
+ if (ref) {
314
+ ref.value = el_2;
315
+ }
316
+ el_2.redraw = function (newProps, newChildren) {
317
+ props = newProps ? __assign(__assign({}, props), newProps) : props;
318
+ children_1 = (newChildren !== null && newChildren !== void 0 ? newChildren : children_1);
319
+ // $ same as above
320
+ var old = el_2;
321
+ el_2 = h(tag, props, children_1);
322
+ el_2.redraw = old.redraw; // inherit redraw
323
+ if (ref) {
324
+ ref.value = el_2;
325
+ }
326
+ old.replaceWith(el_2);
327
+ };
328
+ return el_2;
327
329
  }
328
- return el;
329
330
  }
330
331
  /**
331
332
  * Fragment support - returns an array of children
332
333
  * Note: kt.js doesn't have a real Fragment concept,
333
334
  */
334
335
  function Fragment(props) {
335
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
336
- // const { children } = props || {};
336
+ throw new Error("kt.js doesn't have a Fragment concept");
337
+ // const { children } = props ?? {};
337
338
  // if (!children) {
338
339
  // return ;
339
340
  // }
package/dist/index.mjs CHANGED
@@ -2,33 +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
- (() => {
16
- const runtimeKey = '__ktjs__';
17
- if (runtimeKey in window) {
18
- return;
19
- }
20
- const __ktjs__ = Object.create(null);
21
- // & We can add new functions when we need more
22
- const descriptor = {
23
- throws: { value: $throw, enumerable: true },
24
- defines: { value: $defines, enumerable: true },
25
- mark: { value: $mark, enumerable: true },
26
- };
27
- $defines(__ktjs__, descriptor);
28
- $defines(window, { [runtimeKey]: { value: __ktjs__, enumerable: true } });
29
- return {};
30
- })();
31
-
32
5
  /**
33
6
  * & Remove `bind` because it is shockingly slower than wrapper
34
7
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -67,6 +40,14 @@ const $append = // for ie 9/10/11
67
40
  }
68
41
  };
69
42
 
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
+
70
51
  function booleanHandler(element, key, value) {
71
52
  if (key in element) {
72
53
  element[key] = !!value;
@@ -222,7 +203,7 @@ function applyContent(element, content) {
222
203
  * ## About
223
204
  * @package @ktjs/core
224
205
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
225
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
206
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
226
207
  * @license MIT
227
208
  * @link https://github.com/baendlorel/kt.js
228
209
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -240,45 +221,67 @@ const h = ((tag, attr = '', content = '') => {
240
221
  applyContent(element, content);
241
222
  return element;
242
223
  });
243
- $mark(h, 'h');
244
224
 
245
225
  /**
246
226
  * @param tag html tag or function component
247
227
  * @param props properties/attributes
248
- * @param _metadata metadata is ignored
249
228
  */
250
- function jsx(tag, props, ..._metadata) {
229
+ function jsx(tag, props = {}) {
230
+ const ref = props.ref?.isKT ? props.ref : null;
231
+ if (ref) {
232
+ delete props.ref;
233
+ }
251
234
  // Handle function components
252
235
  if (typeof tag === 'function') {
253
- const propObj = typeof props === 'string' ? { class: props } : props || {};
254
- const children = propObj.children;
255
- return tag({ ...propObj, children });
256
- }
257
- // Handle regular HTML tags
258
- const propObj = typeof props === 'string' ? { class: props } : props;
259
- if (propObj === undefined || propObj === null) {
260
- return h(tag);
261
- }
262
- const children = propObj.children;
263
- delete propObj.children;
264
- // deal with ref attribute
265
- const ref = propObj.ref?.isKT ? propObj.ref : null;
266
- if (ref) {
267
- delete propObj.ref;
236
+ let el = tag(props);
237
+ if (!el.redraw) {
238
+ el.redraw = (newProps) => {
239
+ props = newProps ? { ...props, ...newProps } : props;
240
+ // $ same as below
241
+ const old = el;
242
+ el = tag(props);
243
+ el.redraw = old.redraw; // inherit redraw
244
+ if (ref) {
245
+ ref.value = el;
246
+ }
247
+ old.replaceWith(el);
248
+ };
249
+ }
250
+ if (ref) {
251
+ ref.value = el;
252
+ }
253
+ return el;
268
254
  }
269
- const el = h(tag, propObj, children);
270
- if (ref) {
271
- ref.value = el;
255
+ else {
256
+ // & deal children here
257
+ let children = props.children;
258
+ delete props.children;
259
+ let el = h(tag, props, children);
260
+ if (ref) {
261
+ ref.value = el;
262
+ }
263
+ el.redraw = (newProps, newChildren) => {
264
+ props = newProps ? { ...props, ...newProps } : props;
265
+ children = (newChildren ?? children);
266
+ // $ same as above
267
+ const old = el;
268
+ el = h(tag, props, children);
269
+ el.redraw = old.redraw; // inherit redraw
270
+ if (ref) {
271
+ ref.value = el;
272
+ }
273
+ old.replaceWith(el);
274
+ };
275
+ return el;
272
276
  }
273
- return el;
274
277
  }
275
278
  /**
276
279
  * Fragment support - returns an array of children
277
280
  * Note: kt.js doesn't have a real Fragment concept,
278
281
  */
279
282
  function Fragment(props) {
280
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
281
- // const { children } = props || {};
283
+ throw new Error("kt.js doesn't have a Fragment concept");
284
+ // const { children } = props ?? {};
282
285
  // if (!children) {
283
286
  // return ;
284
287
  // }
@@ -94,6 +94,33 @@ type KTPrefixedEventHandlers = {
94
94
 
95
95
  type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
96
96
 
97
+ type KTHTMLElement = HTMLElement & {
98
+ /**
99
+ * Automically generate a redraw function if it is not provided
100
+ * @param props
101
+ */
102
+ redraw: (props?: KTAttribute, children?: KTRawContent) => void;
103
+ };
104
+
105
+ declare global {
106
+ namespace JSX {
107
+ type Element = KTHTMLElement;
108
+
109
+ interface IntrinsicElements {
110
+ [tag: string]: KTAttribute & { children?: KTRawContent };
111
+ }
112
+
113
+ // interface IntrinsicAttributes {
114
+ // key?: string | number;
115
+ // }
116
+ type IntrinsicAttributes = KTAttribute;
117
+
118
+ interface ElementChildrenAttribute {
119
+ children: {};
120
+ }
121
+ }
122
+ }
123
+
97
124
  type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagNameMap[T] : HTMLElement;
98
125
  type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent) => HTML<T>) & {
99
126
  kDepth: number;
@@ -109,7 +136,7 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
109
136
  * ## About
110
137
  * @package @ktjs/core
111
138
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
112
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
139
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
113
140
  * @license MIT
114
141
  * @link https://github.com/baendlorel/kt.js
115
142
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -118,12 +145,12 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
118
145
  */
119
146
  declare const h: H;
120
147
 
148
+ type JSXTag = HTMLTag | ((props?: any) => HTMLElement) | ((props?: any) => Promise<HTMLElement>) | ((props?: any) => KTHTMLElement) | ((props?: any) => Promise<KTHTMLElement>);
121
149
  /**
122
150
  * @param tag html tag or function component
123
151
  * @param props properties/attributes
124
- * @param _metadata metadata is ignored
125
152
  */
126
- declare function jsx<T extends HTMLTag>(tag: T | Function, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T] | HTMLElement;
153
+ declare function jsx(tag: JSXTag, props?: KTAttribute): KTHTMLElement;
127
154
  /**
128
155
  * Fragment support - returns an array of children
129
156
  * Note: kt.js doesn't have a real Fragment concept,
@@ -141,24 +168,5 @@ declare const jsxDEV: typeof jsx;
141
168
  */
142
169
  declare const jsxs: typeof jsx;
143
170
 
144
- declare global {
145
- namespace JSX {
146
- type Element = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
147
-
148
- interface IntrinsicElements {
149
- [tag: string]: KTAttribute & { children?: KTRawContent };
150
- }
151
-
152
- // interface IntrinsicAttributes {
153
- // key?: string | number;
154
- // }
155
- type IntrinsicAttributes = KTAttribute;
156
-
157
- interface ElementChildrenAttribute {
158
- children: {};
159
- }
160
- }
161
- }
162
-
163
171
  export { Fragment, h as createElement, jsx, jsxDEV, jsxs, ref };
164
- export type { KTRef };
172
+ export type { KTHTMLElement, KTRef };
@@ -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,6 +40,14 @@ const $append = // for ie 9/10/11
50
40
  }
51
41
  };
52
42
 
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
+
53
51
  function booleanHandler(element, key, value) {
54
52
  if (key in element) {
55
53
  element[key] = !!value;
@@ -205,7 +203,7 @@ function applyContent(element, content) {
205
203
  * ## About
206
204
  * @package @ktjs/core
207
205
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
208
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
206
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
209
207
  * @license MIT
210
208
  * @link https://github.com/baendlorel/kt.js
211
209
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -223,45 +221,67 @@ const h = ((tag, attr = '', content = '') => {
223
221
  applyContent(element, content);
224
222
  return element;
225
223
  });
226
- $mark(h, 'h');
227
224
 
228
225
  /**
229
226
  * @param tag html tag or function component
230
227
  * @param props properties/attributes
231
- * @param _metadata metadata is ignored
232
228
  */
233
- function jsx(tag, props, ..._metadata) {
229
+ function jsx(tag, props = {}) {
230
+ const ref = props.ref?.isKT ? props.ref : null;
231
+ if (ref) {
232
+ delete props.ref;
233
+ }
234
234
  // Handle function components
235
235
  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;
236
+ let el = tag(props);
237
+ if (!el.redraw) {
238
+ el.redraw = (newProps) => {
239
+ props = newProps ? { ...props, ...newProps } : props;
240
+ // $ same as below
241
+ const old = el;
242
+ el = tag(props);
243
+ el.redraw = old.redraw; // inherit redraw
244
+ if (ref) {
245
+ ref.value = el;
246
+ }
247
+ old.replaceWith(el);
248
+ };
249
+ }
250
+ if (ref) {
251
+ ref.value = el;
252
+ }
253
+ return el;
251
254
  }
252
- const el = h(tag, propObj, children);
253
- if (ref) {
254
- ref.value = el;
255
+ else {
256
+ // & deal children here
257
+ let children = props.children;
258
+ delete props.children;
259
+ let el = h(tag, props, children);
260
+ if (ref) {
261
+ ref.value = el;
262
+ }
263
+ el.redraw = (newProps, newChildren) => {
264
+ props = newProps ? { ...props, ...newProps } : props;
265
+ children = (newChildren ?? children);
266
+ // $ same as above
267
+ const old = el;
268
+ el = h(tag, props, children);
269
+ el.redraw = old.redraw; // inherit redraw
270
+ if (ref) {
271
+ ref.value = el;
272
+ }
273
+ old.replaceWith(el);
274
+ };
275
+ return el;
255
276
  }
256
- return el;
257
277
  }
258
278
  /**
259
279
  * Fragment support - returns an array of children
260
280
  * Note: kt.js doesn't have a real Fragment concept,
261
281
  */
262
282
  function Fragment(props) {
263
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
264
- // const { children } = props || {};
283
+ throw new Error("kt.js doesn't have a Fragment concept");
284
+ // const { children } = props ?? {};
265
285
  // if (!children) {
266
286
  // return ;
267
287
  // }
@@ -88,6 +88,33 @@ type KTPrefixedEventHandlers = {
88
88
 
89
89
  type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
90
90
 
91
+ type KTHTMLElement = HTMLElement & {
92
+ /**
93
+ * Automically generate a redraw function if it is not provided
94
+ * @param props
95
+ */
96
+ redraw: (props?: KTAttribute, children?: KTRawContent) => void;
97
+ };
98
+
99
+ declare global {
100
+ namespace JSX {
101
+ type Element = KTHTMLElement;
102
+
103
+ interface IntrinsicElements {
104
+ [tag: string]: KTAttribute & { children?: KTRawContent };
105
+ }
106
+
107
+ // interface IntrinsicAttributes {
108
+ // key?: string | number;
109
+ // }
110
+ type IntrinsicAttributes = KTAttribute;
111
+
112
+ interface ElementChildrenAttribute {
113
+ children: {};
114
+ }
115
+ }
116
+ }
117
+
91
118
  type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagNameMap[T] : HTMLElement;
92
119
  type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent) => HTML<T>) & {
93
120
  kDepth: number;
@@ -103,7 +130,7 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
103
130
  * ## About
104
131
  * @package @ktjs/core
105
132
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
106
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
133
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
107
134
  * @license MIT
108
135
  * @link https://github.com/baendlorel/kt.js
109
136
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -112,12 +139,12 @@ type H = (<T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent)
112
139
  */
113
140
  declare const h: H;
114
141
 
142
+ type JSXTag = HTMLTag | ((props?: any) => HTMLElement) | ((props?: any) => Promise<HTMLElement>) | ((props?: any) => KTHTMLElement) | ((props?: any) => Promise<KTHTMLElement>);
115
143
  /**
116
144
  * @param tag html tag or function component
117
145
  * @param props properties/attributes
118
- * @param _metadata metadata is ignored
119
146
  */
120
- declare function jsx<T extends HTMLTag>(tag: T | Function, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T] | HTMLElement;
147
+ declare function jsx(tag: JSXTag, props?: KTAttribute): KTHTMLElement;
121
148
  /**
122
149
  * Fragment support - returns an array of children
123
150
  * 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,6 +40,14 @@ const $append = // for ie 9/10/11
50
40
  }
51
41
  };
52
42
 
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
+
53
51
  function booleanHandler(element, key, value) {
54
52
  if (key in element) {
55
53
  element[key] = !!value;
@@ -205,7 +203,7 @@ function applyContent(element, content) {
205
203
  * ## About
206
204
  * @package @ktjs/core
207
205
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
208
- * @version 0.12.0 (Last Update: 2026.01.14 15:48:26.320)
206
+ * @version 0.13.0 (Last Update: 2026.01.15 16:05:51.084)
209
207
  * @license MIT
210
208
  * @link https://github.com/baendlorel/kt.js
211
209
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -223,45 +221,67 @@ const h = ((tag, attr = '', content = '') => {
223
221
  applyContent(element, content);
224
222
  return element;
225
223
  });
226
- $mark(h, 'h');
227
224
 
228
225
  /**
229
226
  * @param tag html tag or function component
230
227
  * @param props properties/attributes
231
- * @param _metadata metadata is ignored
232
228
  */
233
- function jsx(tag, props, ..._metadata) {
229
+ function jsx(tag, props = {}) {
230
+ const ref = props.ref?.isKT ? props.ref : null;
231
+ if (ref) {
232
+ delete props.ref;
233
+ }
234
234
  // Handle function components
235
235
  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;
236
+ let el = tag(props);
237
+ if (!el.redraw) {
238
+ el.redraw = (newProps) => {
239
+ props = newProps ? { ...props, ...newProps } : props;
240
+ // $ same as below
241
+ const old = el;
242
+ el = tag(props);
243
+ el.redraw = old.redraw; // inherit redraw
244
+ if (ref) {
245
+ ref.value = el;
246
+ }
247
+ old.replaceWith(el);
248
+ };
249
+ }
250
+ if (ref) {
251
+ ref.value = el;
252
+ }
253
+ return el;
251
254
  }
252
- const el = h(tag, propObj, children);
253
- if (ref) {
254
- ref.value = el;
255
+ else {
256
+ // & deal children here
257
+ let children = props.children;
258
+ delete props.children;
259
+ let el = h(tag, props, children);
260
+ if (ref) {
261
+ ref.value = el;
262
+ }
263
+ el.redraw = (newProps, newChildren) => {
264
+ props = newProps ? { ...props, ...newProps } : props;
265
+ children = (newChildren ?? children);
266
+ // $ same as above
267
+ const old = el;
268
+ el = h(tag, props, children);
269
+ el.redraw = old.redraw; // inherit redraw
270
+ if (ref) {
271
+ ref.value = el;
272
+ }
273
+ old.replaceWith(el);
274
+ };
275
+ return el;
255
276
  }
256
- return el;
257
277
  }
258
278
  /**
259
279
  * Fragment support - returns an array of children
260
280
  * Note: kt.js doesn't have a real Fragment concept,
261
281
  */
262
282
  function Fragment(props) {
263
- window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
264
- // const { children } = props || {};
283
+ throw new Error("kt.js doesn't have a Fragment concept");
284
+ // const { children } = props ?? {};
265
285
  // if (!children) {
266
286
  // return ;
267
287
  // }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
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",