@ktjs/core 0.7.3 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +53 -6
- package/dist/index.iife.js +95 -89
- package/dist/index.legacy.js +131 -89
- package/dist/index.mjs +89 -89
- package/dist/jsx/index.d.ts +129 -0
- package/dist/jsx/index.mjs +296 -0
- package/dist/jsx/jsx-runtime.d.ts +128 -0
- package/dist/jsx/jsx-runtime.mjs +293 -0
- package/package.json +19 -5
package/dist/index.mjs
CHANGED
|
@@ -172,19 +172,25 @@ function applyAttr(element, attr) {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
const noop = () => ({});
|
|
176
|
+
class Ref {
|
|
177
|
+
value;
|
|
178
|
+
update;
|
|
179
|
+
constructor(value) {
|
|
180
|
+
this.value = value;
|
|
181
|
+
this.update = noop;
|
|
179
182
|
}
|
|
183
|
+
}
|
|
184
|
+
function ref(value) {
|
|
185
|
+
return new Ref(value);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function applyContent(element, content) {
|
|
180
189
|
if ($isArray(content)) {
|
|
181
190
|
for (let i = 0; i < content.length; i++) {
|
|
182
191
|
let c = content[i];
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
else if (typeof c === 'number') {
|
|
187
|
-
$append.call(element, c.toString());
|
|
192
|
+
if (c instanceof Ref) {
|
|
193
|
+
$append.call(element, c.value);
|
|
188
194
|
}
|
|
189
195
|
else {
|
|
190
196
|
$append.call(element, c);
|
|
@@ -192,8 +198,8 @@ function applyContent(element, content) {
|
|
|
192
198
|
}
|
|
193
199
|
}
|
|
194
200
|
else {
|
|
195
|
-
if (
|
|
196
|
-
$append.call(element, content.
|
|
201
|
+
if (content instanceof Ref) {
|
|
202
|
+
$append.call(element, content.value);
|
|
197
203
|
}
|
|
198
204
|
else {
|
|
199
205
|
$append.call(element, content);
|
|
@@ -211,11 +217,11 @@ function applyContent(element, content) {
|
|
|
211
217
|
* ## About
|
|
212
218
|
* @package @ktjs/core
|
|
213
219
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
214
|
-
* @version 0.
|
|
220
|
+
* @version 0.8.1 (Last Update: 2025.12.25 11:07:30.486)
|
|
215
221
|
* @license MIT
|
|
216
222
|
* @link https://github.com/baendlorel/kt.js
|
|
217
223
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
218
|
-
* @description Core functionality for kt.js - DOM manipulation utilities
|
|
224
|
+
* @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
|
|
219
225
|
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
220
226
|
*/
|
|
221
227
|
const h = (tag, attr = '', content = '') => {
|
|
@@ -232,82 +238,76 @@ const h = (tag, attr = '', content = '') => {
|
|
|
232
238
|
$mark(h, 'h');
|
|
233
239
|
|
|
234
240
|
/**
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
* While we have no need to have `ktext` for `<br>` tags.
|
|
239
|
-
*
|
|
240
|
-
* ## Tags where appending a text node has no effect
|
|
241
|
-
*
|
|
242
|
-
* There are some HTML elements that appending a text node as their child takes no effect.
|
|
243
|
-
* They are mostly void elements, but some non-void elements are also included.
|
|
244
|
-
*
|
|
245
|
-
* ## What means no effect
|
|
246
|
-
* 1. appending a text node to these tags takes no effect.
|
|
247
|
-
* 2. No effect means `innerText` does not include the text in the text node.
|
|
248
|
-
*
|
|
249
|
-
* After testing 15 browsers testing, I found that these elements are:
|
|
250
|
-
*
|
|
251
|
-
* - FireFox(as base):
|
|
252
|
-
* - script -- this is skipped due to some bugs in The World 7
|
|
253
|
-
* - area, audio, base, basefont, br, canvas, datalist, details, dialog, frameset, head, iframe, img, input, link, meta, meter, noembed, noframes, noscript, optgroup, param, progress, rp, select, style, template, textarea, title, video, wbr
|
|
254
|
-
* - 360: embed
|
|
255
|
-
* - 2345: embed
|
|
256
|
-
* - maxthon: embed
|
|
257
|
-
* - quark: embed
|
|
258
|
-
* - uc: embed
|
|
259
|
-
* - chrome: embed,frame
|
|
260
|
-
* - qq: embed
|
|
261
|
-
* - sogou: embed
|
|
262
|
-
* - cent: embed
|
|
263
|
-
* - world: embed,frame,keygen,option
|
|
264
|
-
* - opera: embed
|
|
265
|
-
* - edge: embed
|
|
266
|
-
* - liebao: embed
|
|
267
|
-
* - 360turbo: embed,frame
|
|
268
|
-
*
|
|
269
|
-
* Since `Set.prototype.has` is about 80 times faster than `Array.prototype.includes`,
|
|
270
|
-
* We put these tags into a `Set` object.
|
|
241
|
+
* @param tag html tag
|
|
242
|
+
* @param props properties/attributes
|
|
243
|
+
* @param _metadata metadata is ignored
|
|
271
244
|
*/
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
245
|
+
function jsx(tag, props, ..._metadata) {
|
|
246
|
+
const propObj = typeof props === 'string' ? { class: props } : props;
|
|
247
|
+
if (propObj === undefined || propObj === null) {
|
|
248
|
+
return h(tag);
|
|
249
|
+
}
|
|
250
|
+
const children = propObj.children;
|
|
251
|
+
delete propObj.children;
|
|
252
|
+
// deal with ref attribute
|
|
253
|
+
const ref = 'ref' in propObj && propObj.ref instanceof Ref ? propObj.ref : null;
|
|
254
|
+
if (ref) {
|
|
255
|
+
delete propObj.ref;
|
|
256
|
+
}
|
|
257
|
+
const el = h(tag, propObj, children);
|
|
258
|
+
if (ref) {
|
|
259
|
+
ref.value = el;
|
|
260
|
+
ref.update = () => {
|
|
261
|
+
const old = ref.value;
|
|
262
|
+
ref.value = h(tag, propObj, children);
|
|
263
|
+
old.replaceWith(ref.value);
|
|
264
|
+
return ref.value;
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return el;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Fragment support - returns an array of children
|
|
271
|
+
* Note: kt.js doesn't have a real Fragment concept,
|
|
272
|
+
* so we return ktnull for empty fragments or flatten children
|
|
273
|
+
*/
|
|
274
|
+
function Fragment(props) {
|
|
275
|
+
window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
|
|
276
|
+
// const { children } = props || {};
|
|
277
|
+
// if (!children) {
|
|
278
|
+
// return ktnull;
|
|
279
|
+
// }
|
|
280
|
+
// // If single child, return it directly
|
|
281
|
+
// if (!Array.isArray(children)) {
|
|
282
|
+
// return children as HTMLElement;
|
|
283
|
+
// }
|
|
284
|
+
// // For multiple children, create a document fragment wrapper
|
|
285
|
+
// // This is a limitation - JSX fragments must be wrapped in kt.js
|
|
286
|
+
// const wrapper = document.createElement('div');
|
|
287
|
+
// wrapper.setAttribute('data-kt-fragment', 'true');
|
|
288
|
+
// children.forEach((child) => {
|
|
289
|
+
// if (child && child !== ktnull) {
|
|
290
|
+
// if (typeof child === 'string') {
|
|
291
|
+
// wrapper.appendChild(document.createTextNode(child));
|
|
292
|
+
// } else if (child instanceof HTMLElement) {
|
|
293
|
+
// wrapper.appendChild(child);
|
|
294
|
+
// }
|
|
295
|
+
// }
|
|
296
|
+
// });
|
|
297
|
+
// return wrapper;
|
|
311
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* JSX Development runtime - same as jsx but with additional dev checks
|
|
301
|
+
*/
|
|
302
|
+
const jsxDEV = (...args) => {
|
|
303
|
+
console.log('JSX DEV called:', ...args);
|
|
304
|
+
console.log('chilren', args[1]?.children);
|
|
305
|
+
return jsx(...args);
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* JSX runtime for React 17+ automatic runtime
|
|
309
|
+
* This is called when using jsx: "react-jsx" or "react-jsxdev"
|
|
310
|
+
*/
|
|
311
|
+
const jsxs = jsx;
|
|
312
312
|
|
|
313
|
-
export { h, ktnull,
|
|
313
|
+
export { Fragment, Ref, h as createElement, h, jsx, jsxDEV, jsxs, ktnull, ref };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
type otherstring = string & {};
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Normal HTML tags like `div`, `span`, `a`, etc.
|
|
5
|
+
*/
|
|
6
|
+
type HTMLTag = keyof HTMLElementTagNameMap & otherstring;
|
|
7
|
+
|
|
8
|
+
declare class Ref<T> {
|
|
9
|
+
value: T;
|
|
10
|
+
update: () => T;
|
|
11
|
+
constructor(value: T);
|
|
12
|
+
}
|
|
13
|
+
declare function ref<T>(value: T): Ref<T>;
|
|
14
|
+
|
|
15
|
+
type Ctt = Ref<any> | HTMLElement | string | number | undefined;
|
|
16
|
+
type KTRawContent = Ctt[] | Ctt;
|
|
17
|
+
type KTRawAttr = KTAttribute | string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Used to create enhanced HTML elements
|
|
21
|
+
*/
|
|
22
|
+
interface KTBaseAttribute {
|
|
23
|
+
[k: string]: any;
|
|
24
|
+
|
|
25
|
+
id?: string;
|
|
26
|
+
class?: string;
|
|
27
|
+
style?: string | Partial<CSSStyleDeclaration>;
|
|
28
|
+
|
|
29
|
+
type?:
|
|
30
|
+
| 'text'
|
|
31
|
+
| 'password'
|
|
32
|
+
| 'email'
|
|
33
|
+
| 'number'
|
|
34
|
+
| 'tel'
|
|
35
|
+
| 'url'
|
|
36
|
+
| 'search'
|
|
37
|
+
| 'date'
|
|
38
|
+
| 'datetime-local'
|
|
39
|
+
| 'time'
|
|
40
|
+
| 'month'
|
|
41
|
+
| 'week'
|
|
42
|
+
| 'color'
|
|
43
|
+
| 'range'
|
|
44
|
+
| 'file'
|
|
45
|
+
| 'checkbox'
|
|
46
|
+
| 'radio'
|
|
47
|
+
| 'hidden'
|
|
48
|
+
| 'submit'
|
|
49
|
+
| 'reset'
|
|
50
|
+
| 'button'
|
|
51
|
+
| 'image'
|
|
52
|
+
| otherstring;
|
|
53
|
+
for?: string;
|
|
54
|
+
|
|
55
|
+
name?: string;
|
|
56
|
+
value?: string;
|
|
57
|
+
valueAsDate?: Date;
|
|
58
|
+
valueAsNumber?: number;
|
|
59
|
+
label?: string;
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
|
|
62
|
+
min?: string | number;
|
|
63
|
+
max?: string | number;
|
|
64
|
+
step?: string | number;
|
|
65
|
+
|
|
66
|
+
selected?: boolean;
|
|
67
|
+
checked?: boolean;
|
|
68
|
+
|
|
69
|
+
action?: string;
|
|
70
|
+
method?: 'POST' | 'GET' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' | otherstring;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type KTPrefixedEventHandlers = {
|
|
74
|
+
[EventName in keyof HTMLElementEventMap as `on:${EventName}`]?: (ev: HTMLElementEventMap[EventName]) => void;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
|
|
78
|
+
|
|
79
|
+
type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagNameMap[T] : HTMLElement;
|
|
80
|
+
/**
|
|
81
|
+
* Create an enhanced HTMLElement.
|
|
82
|
+
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
83
|
+
* @param tag tag of an `HTMLElement`
|
|
84
|
+
* @param attr attribute object or className
|
|
85
|
+
* @param content a string or an array of HTMLEnhancedElement as child nodes
|
|
86
|
+
*
|
|
87
|
+
* ## About
|
|
88
|
+
* @package @ktjs/core
|
|
89
|
+
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
90
|
+
* @version 0.8.1 (Last Update: 2025.12.25 11:07:30.486)
|
|
91
|
+
* @license MIT
|
|
92
|
+
* @link https://github.com/baendlorel/kt.js
|
|
93
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
94
|
+
* @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
|
|
95
|
+
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
96
|
+
*/
|
|
97
|
+
declare const h: <T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent) => HTML<T>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* This is a `falsy` value used to indicate "no node" in `h` function.
|
|
101
|
+
* - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
|
|
102
|
+
*/
|
|
103
|
+
declare const ktnull: any;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param tag html tag
|
|
107
|
+
* @param props properties/attributes
|
|
108
|
+
* @param _metadata metadata is ignored
|
|
109
|
+
*/
|
|
110
|
+
declare function jsx<T extends HTMLTag>(tag: T, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T];
|
|
111
|
+
/**
|
|
112
|
+
* Fragment support - returns an array of children
|
|
113
|
+
* Note: kt.js doesn't have a real Fragment concept,
|
|
114
|
+
* so we return ktnull for empty fragments or flatten children
|
|
115
|
+
*/
|
|
116
|
+
declare function Fragment(props: {
|
|
117
|
+
children?: KTRawContent;
|
|
118
|
+
}): HTMLElement | typeof ktnull;
|
|
119
|
+
/**
|
|
120
|
+
* JSX Development runtime - same as jsx but with additional dev checks
|
|
121
|
+
*/
|
|
122
|
+
declare const jsxDEV: typeof jsx;
|
|
123
|
+
/**
|
|
124
|
+
* JSX runtime for React 17+ automatic runtime
|
|
125
|
+
* This is called when using jsx: "react-jsx" or "react-jsxdev"
|
|
126
|
+
*/
|
|
127
|
+
declare const jsxs: typeof jsx;
|
|
128
|
+
|
|
129
|
+
export { Fragment, Ref, h as createElement, jsx, jsxDEV, jsxs, ref };
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
const $throw = (message) => {
|
|
2
|
+
throw new Error('kt.js: ' + message);
|
|
3
|
+
};
|
|
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
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This is a `falsy` value used to indicate "no node" in `h` function.
|
|
16
|
+
* - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
|
|
17
|
+
*/
|
|
18
|
+
const ktnull = Object.create(null);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
22
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
23
|
+
*/
|
|
24
|
+
const $appendChild = HTMLElement.prototype.appendChild;
|
|
25
|
+
const originAppend = HTMLElement.prototype.append;
|
|
26
|
+
const $append = // for ie 9/10/11
|
|
27
|
+
typeof originAppend === 'function'
|
|
28
|
+
? function (...args) {
|
|
29
|
+
const nodes = args.filter((a) => a !== ktnull);
|
|
30
|
+
return originAppend.apply(this, nodes);
|
|
31
|
+
}
|
|
32
|
+
: function (...nodes) {
|
|
33
|
+
if (nodes.length < 50) {
|
|
34
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
35
|
+
const node = nodes[i];
|
|
36
|
+
if (typeof node === 'string') {
|
|
37
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
38
|
+
}
|
|
39
|
+
else if (node !== ktnull) {
|
|
40
|
+
$appendChild.call(this, node);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const fragment = document.createDocumentFragment();
|
|
46
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
47
|
+
const node = nodes[i];
|
|
48
|
+
if (typeof node === 'string') {
|
|
49
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
50
|
+
}
|
|
51
|
+
else if (node !== ktnull) {
|
|
52
|
+
$appendChild.call(fragment, node);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
$appendChild.call(this, fragment);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function booleanHandler(element, key, value) {
|
|
60
|
+
if (key in element) {
|
|
61
|
+
element[key] = !!value;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
element.setAttribute(key, value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function valueHandler(element, key, value) {
|
|
68
|
+
if (key in element) {
|
|
69
|
+
element[key] = value;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
element.setAttribute(key, value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Attribute handlers map for optimized lookup
|
|
76
|
+
const handlers = {
|
|
77
|
+
checked: booleanHandler,
|
|
78
|
+
selected: booleanHandler,
|
|
79
|
+
value: valueHandler,
|
|
80
|
+
valueAsDate: valueHandler,
|
|
81
|
+
valueAsNumber: valueHandler,
|
|
82
|
+
defaultValue: valueHandler,
|
|
83
|
+
defaultChecked: booleanHandler,
|
|
84
|
+
defaultSelected: booleanHandler,
|
|
85
|
+
disabled: booleanHandler,
|
|
86
|
+
readOnly: booleanHandler,
|
|
87
|
+
multiple: booleanHandler,
|
|
88
|
+
required: booleanHandler,
|
|
89
|
+
autofocus: booleanHandler,
|
|
90
|
+
open: booleanHandler,
|
|
91
|
+
controls: booleanHandler,
|
|
92
|
+
autoplay: booleanHandler,
|
|
93
|
+
loop: booleanHandler,
|
|
94
|
+
muted: booleanHandler,
|
|
95
|
+
defer: booleanHandler,
|
|
96
|
+
async: booleanHandler,
|
|
97
|
+
hidden: function (element, _key, value) {
|
|
98
|
+
element.hidden = !!value;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
const defaultHandler = function (element, key, value) {
|
|
102
|
+
return element.setAttribute(key, value);
|
|
103
|
+
};
|
|
104
|
+
function attrIsObject(element, attr) {
|
|
105
|
+
const classValue = attr.class;
|
|
106
|
+
const style = attr.style;
|
|
107
|
+
if (classValue !== undefined) {
|
|
108
|
+
element.className = classValue;
|
|
109
|
+
delete attr.class;
|
|
110
|
+
}
|
|
111
|
+
if (style) {
|
|
112
|
+
if (typeof style === 'string') {
|
|
113
|
+
element.setAttribute('style', style);
|
|
114
|
+
}
|
|
115
|
+
else if (typeof style === 'object') {
|
|
116
|
+
for (const key in style) {
|
|
117
|
+
element.style[key] = style[key];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
delete attr.style;
|
|
121
|
+
}
|
|
122
|
+
const keys = $keys(attr);
|
|
123
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
124
|
+
const key = keys[i];
|
|
125
|
+
const o = attr[key];
|
|
126
|
+
// force register on:xxx as an event handler
|
|
127
|
+
// !if o is not valid, the throwing job will be done by `on`, not kt.js
|
|
128
|
+
if (key.startsWith('on:')) {
|
|
129
|
+
element.addEventListener(key.slice(3), o); // chop off the `@`
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (typeof o === 'function') {
|
|
133
|
+
(handlers[key] || defaultHandler)(element, key, o());
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
(handlers[key] || defaultHandler)(element, key, o);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (classValue !== undefined) {
|
|
140
|
+
attr.class = classValue;
|
|
141
|
+
}
|
|
142
|
+
if (style !== undefined) {
|
|
143
|
+
attr.style = style;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function applyAttr(element, attr) {
|
|
147
|
+
if (typeof attr === 'string') {
|
|
148
|
+
element.className = attr;
|
|
149
|
+
}
|
|
150
|
+
else if (typeof attr === 'object' && attr !== null) {
|
|
151
|
+
attrIsObject(element, attr);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
$throw('attr must be an object/string.');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const noop = () => ({});
|
|
159
|
+
class Ref {
|
|
160
|
+
value;
|
|
161
|
+
update;
|
|
162
|
+
constructor(value) {
|
|
163
|
+
this.value = value;
|
|
164
|
+
this.update = noop;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function ref(value) {
|
|
168
|
+
return new Ref(value);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function applyContent(element, content) {
|
|
172
|
+
if ($isArray(content)) {
|
|
173
|
+
for (let i = 0; i < content.length; i++) {
|
|
174
|
+
let c = content[i];
|
|
175
|
+
if (c instanceof Ref) {
|
|
176
|
+
$append.call(element, c.value);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
$append.call(element, c);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
if (content instanceof Ref) {
|
|
185
|
+
$append.call(element, content.value);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
$append.call(element, content);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create an enhanced HTMLElement.
|
|
195
|
+
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
196
|
+
* @param tag tag of an `HTMLElement`
|
|
197
|
+
* @param attr attribute object or className
|
|
198
|
+
* @param content a string or an array of HTMLEnhancedElement as child nodes
|
|
199
|
+
*
|
|
200
|
+
* ## About
|
|
201
|
+
* @package @ktjs/core
|
|
202
|
+
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
203
|
+
* @version 0.8.1 (Last Update: 2025.12.25 11:07:30.486)
|
|
204
|
+
* @license MIT
|
|
205
|
+
* @link https://github.com/baendlorel/kt.js
|
|
206
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
207
|
+
* @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
|
|
208
|
+
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
209
|
+
*/
|
|
210
|
+
const h = (tag, attr = '', content = '') => {
|
|
211
|
+
if (typeof tag !== 'string') {
|
|
212
|
+
$throw('__func__ tagName must be a string.');
|
|
213
|
+
}
|
|
214
|
+
// * start creating the element
|
|
215
|
+
const element = document.createElement(tag);
|
|
216
|
+
// * Handle content
|
|
217
|
+
applyAttr(element, attr);
|
|
218
|
+
applyContent(element, content);
|
|
219
|
+
return element;
|
|
220
|
+
};
|
|
221
|
+
$mark(h, 'h');
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @param tag html tag
|
|
225
|
+
* @param props properties/attributes
|
|
226
|
+
* @param _metadata metadata is ignored
|
|
227
|
+
*/
|
|
228
|
+
function jsx(tag, props, ..._metadata) {
|
|
229
|
+
const propObj = typeof props === 'string' ? { class: props } : props;
|
|
230
|
+
if (propObj === undefined || propObj === null) {
|
|
231
|
+
return h(tag);
|
|
232
|
+
}
|
|
233
|
+
const children = propObj.children;
|
|
234
|
+
delete propObj.children;
|
|
235
|
+
// deal with ref attribute
|
|
236
|
+
const ref = 'ref' in propObj && propObj.ref instanceof Ref ? propObj.ref : null;
|
|
237
|
+
if (ref) {
|
|
238
|
+
delete propObj.ref;
|
|
239
|
+
}
|
|
240
|
+
const el = h(tag, propObj, children);
|
|
241
|
+
if (ref) {
|
|
242
|
+
ref.value = el;
|
|
243
|
+
ref.update = () => {
|
|
244
|
+
const old = ref.value;
|
|
245
|
+
ref.value = h(tag, propObj, children);
|
|
246
|
+
old.replaceWith(ref.value);
|
|
247
|
+
return ref.value;
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return el;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Fragment support - returns an array of children
|
|
254
|
+
* Note: kt.js doesn't have a real Fragment concept,
|
|
255
|
+
* so we return ktnull for empty fragments or flatten children
|
|
256
|
+
*/
|
|
257
|
+
function Fragment(props) {
|
|
258
|
+
window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
|
|
259
|
+
// const { children } = props || {};
|
|
260
|
+
// if (!children) {
|
|
261
|
+
// return ktnull;
|
|
262
|
+
// }
|
|
263
|
+
// // If single child, return it directly
|
|
264
|
+
// if (!Array.isArray(children)) {
|
|
265
|
+
// return children as HTMLElement;
|
|
266
|
+
// }
|
|
267
|
+
// // For multiple children, create a document fragment wrapper
|
|
268
|
+
// // This is a limitation - JSX fragments must be wrapped in kt.js
|
|
269
|
+
// const wrapper = document.createElement('div');
|
|
270
|
+
// wrapper.setAttribute('data-kt-fragment', 'true');
|
|
271
|
+
// children.forEach((child) => {
|
|
272
|
+
// if (child && child !== ktnull) {
|
|
273
|
+
// if (typeof child === 'string') {
|
|
274
|
+
// wrapper.appendChild(document.createTextNode(child));
|
|
275
|
+
// } else if (child instanceof HTMLElement) {
|
|
276
|
+
// wrapper.appendChild(child);
|
|
277
|
+
// }
|
|
278
|
+
// }
|
|
279
|
+
// });
|
|
280
|
+
// return wrapper;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* JSX Development runtime - same as jsx but with additional dev checks
|
|
284
|
+
*/
|
|
285
|
+
const jsxDEV = (...args) => {
|
|
286
|
+
console.log('JSX DEV called:', ...args);
|
|
287
|
+
console.log('chilren', args[1]?.children);
|
|
288
|
+
return jsx(...args);
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* JSX runtime for React 17+ automatic runtime
|
|
292
|
+
* This is called when using jsx: "react-jsx" or "react-jsxdev"
|
|
293
|
+
*/
|
|
294
|
+
const jsxs = jsx;
|
|
295
|
+
|
|
296
|
+
export { Fragment, Ref, h as createElement, jsx, jsxDEV, jsxs, ref };
|