@ktjs/core 0.7.1 → 0.8.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.
@@ -0,0 +1,128 @@
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
+
14
+ type Ctt = Ref<any> | HTMLElement | string | number | undefined;
15
+ type KTRawContent = Ctt[] | Ctt;
16
+ type KTRawAttr = KTAttribute | string;
17
+
18
+ /**
19
+ * Used to create enhanced HTML elements
20
+ */
21
+ interface KTBaseAttribute {
22
+ [k: string]: any;
23
+
24
+ id?: string;
25
+ class?: string;
26
+ style?: string | Partial<CSSStyleDeclaration>;
27
+
28
+ type?:
29
+ | 'text'
30
+ | 'password'
31
+ | 'email'
32
+ | 'number'
33
+ | 'tel'
34
+ | 'url'
35
+ | 'search'
36
+ | 'date'
37
+ | 'datetime-local'
38
+ | 'time'
39
+ | 'month'
40
+ | 'week'
41
+ | 'color'
42
+ | 'range'
43
+ | 'file'
44
+ | 'checkbox'
45
+ | 'radio'
46
+ | 'hidden'
47
+ | 'submit'
48
+ | 'reset'
49
+ | 'button'
50
+ | 'image'
51
+ | otherstring;
52
+ for?: string;
53
+
54
+ name?: string;
55
+ value?: string;
56
+ valueAsDate?: Date;
57
+ valueAsNumber?: number;
58
+ label?: string;
59
+ disabled?: boolean;
60
+
61
+ min?: string | number;
62
+ max?: string | number;
63
+ step?: string | number;
64
+
65
+ selected?: boolean;
66
+ checked?: boolean;
67
+
68
+ action?: string;
69
+ method?: 'POST' | 'GET' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' | otherstring;
70
+ }
71
+
72
+ type KTPrefixedEventHandlers = {
73
+ [EventName in keyof HTMLElementEventMap as `on:${EventName}`]?: (ev: HTMLElementEventMap[EventName]) => void;
74
+ };
75
+
76
+ type KTAttribute = KTBaseAttribute & KTPrefixedEventHandlers;
77
+
78
+ type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagNameMap[T] : HTMLElement;
79
+ /**
80
+ * Create an enhanced HTMLElement.
81
+ * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
82
+ * @param tag tag of an `HTMLElement`
83
+ * @param attr attribute object or className
84
+ * @param content a string or an array of HTMLEnhancedElement as child nodes
85
+ *
86
+ * ## About
87
+ * @package @ktjs/core
88
+ * @author Kasukabe Tsumugi <futami16237@gmail.com>
89
+ * @version 0.8.0 (Last Update: 2025.12.25 11:01:24.676)
90
+ * @license MIT
91
+ * @link https://github.com/baendlorel/kt.js
92
+ * @link https://baendlorel.github.io/ Welcome to my site!
93
+ * @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
94
+ * @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
95
+ */
96
+ declare const h: <T extends HTMLTag>(tag: T, attr?: KTRawAttr, content?: KTRawContent) => HTML<T>;
97
+
98
+ /**
99
+ * This is a `falsy` value used to indicate "no node" in `h` function.
100
+ * - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
101
+ */
102
+ declare const ktnull: any;
103
+
104
+ /**
105
+ * @param tag html tag
106
+ * @param props properties/attributes
107
+ * @param _metadata metadata is ignored
108
+ */
109
+ declare function jsx<T extends HTMLTag>(tag: T, props: KTRawAttr, ..._metadata: any[]): HTMLElementTagNameMap[T];
110
+ /**
111
+ * Fragment support - returns an array of children
112
+ * Note: kt.js doesn't have a real Fragment concept,
113
+ * so we return ktnull for empty fragments or flatten children
114
+ */
115
+ declare function Fragment(props: {
116
+ children?: KTRawContent;
117
+ }): HTMLElement | typeof ktnull;
118
+ /**
119
+ * JSX Development runtime - same as jsx but with additional dev checks
120
+ */
121
+ declare const jsxDEV: typeof jsx;
122
+ /**
123
+ * JSX runtime for React 17+ automatic runtime
124
+ * This is called when using jsx: "react-jsx" or "react-jsxdev"
125
+ */
126
+ declare const jsxs: typeof jsx;
127
+
128
+ export { Fragment, h as createElement, h, jsx, jsxDEV, jsxs };
@@ -0,0 +1,293 @@
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
+
168
+ function applyContent(element, content) {
169
+ if ($isArray(content)) {
170
+ for (let i = 0; i < content.length; i++) {
171
+ let c = content[i];
172
+ if (c instanceof Ref) {
173
+ $append.call(element, c.value);
174
+ }
175
+ else {
176
+ $append.call(element, c);
177
+ }
178
+ }
179
+ }
180
+ else {
181
+ if (content instanceof Ref) {
182
+ $append.call(element, content.value);
183
+ }
184
+ else {
185
+ $append.call(element, content);
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Create an enhanced HTMLElement.
192
+ * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
193
+ * @param tag tag of an `HTMLElement`
194
+ * @param attr attribute object or className
195
+ * @param content a string or an array of HTMLEnhancedElement as child nodes
196
+ *
197
+ * ## About
198
+ * @package @ktjs/core
199
+ * @author Kasukabe Tsumugi <futami16237@gmail.com>
200
+ * @version 0.8.0 (Last Update: 2025.12.25 11:01:24.676)
201
+ * @license MIT
202
+ * @link https://github.com/baendlorel/kt.js
203
+ * @link https://baendlorel.github.io/ Welcome to my site!
204
+ * @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
205
+ * @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
206
+ */
207
+ const h = (tag, attr = '', content = '') => {
208
+ if (typeof tag !== 'string') {
209
+ $throw('__func__ tagName must be a string.');
210
+ }
211
+ // * start creating the element
212
+ const element = document.createElement(tag);
213
+ // * Handle content
214
+ applyAttr(element, attr);
215
+ applyContent(element, content);
216
+ return element;
217
+ };
218
+ $mark(h, 'h');
219
+
220
+ /**
221
+ * @param tag html tag
222
+ * @param props properties/attributes
223
+ * @param _metadata metadata is ignored
224
+ */
225
+ function jsx(tag, props, ..._metadata) {
226
+ const propObj = typeof props === 'string' ? { class: props } : props;
227
+ if (propObj === undefined || propObj === null) {
228
+ return h(tag);
229
+ }
230
+ const children = propObj.children;
231
+ delete propObj.children;
232
+ // deal with ref attribute
233
+ const ref = 'ref' in propObj && propObj.ref instanceof Ref ? propObj.ref : null;
234
+ if (ref) {
235
+ delete propObj.ref;
236
+ }
237
+ const el = h(tag, propObj, children);
238
+ if (ref) {
239
+ ref.value = el;
240
+ ref.update = () => {
241
+ const old = ref.value;
242
+ ref.value = h(tag, propObj, children);
243
+ old.replaceWith(ref.value);
244
+ return ref.value;
245
+ };
246
+ }
247
+ return el;
248
+ }
249
+ /**
250
+ * Fragment support - returns an array of children
251
+ * Note: kt.js doesn't have a real Fragment concept,
252
+ * so we return ktnull for empty fragments or flatten children
253
+ */
254
+ function Fragment(props) {
255
+ window.__ktjs__.throws("kt.js doesn't have a Fragment concept");
256
+ // const { children } = props || {};
257
+ // if (!children) {
258
+ // return ktnull;
259
+ // }
260
+ // // If single child, return it directly
261
+ // if (!Array.isArray(children)) {
262
+ // return children as HTMLElement;
263
+ // }
264
+ // // For multiple children, create a document fragment wrapper
265
+ // // This is a limitation - JSX fragments must be wrapped in kt.js
266
+ // const wrapper = document.createElement('div');
267
+ // wrapper.setAttribute('data-kt-fragment', 'true');
268
+ // children.forEach((child) => {
269
+ // if (child && child !== ktnull) {
270
+ // if (typeof child === 'string') {
271
+ // wrapper.appendChild(document.createTextNode(child));
272
+ // } else if (child instanceof HTMLElement) {
273
+ // wrapper.appendChild(child);
274
+ // }
275
+ // }
276
+ // });
277
+ // return wrapper;
278
+ }
279
+ /**
280
+ * JSX Development runtime - same as jsx but with additional dev checks
281
+ */
282
+ const jsxDEV = (...args) => {
283
+ console.log('JSX DEV called:', ...args);
284
+ console.log('chilren', args[1]?.children);
285
+ return jsx(...args);
286
+ };
287
+ /**
288
+ * JSX runtime for React 17+ automatic runtime
289
+ * This is called when using jsx: "react-jsx" or "react-jsxdev"
290
+ */
291
+ const jsxs = jsx;
292
+
293
+ export { Fragment, h as createElement, h, jsx, jsxDEV, jsxs };
package/package.json CHANGED
@@ -1,14 +1,28 @@
1
1
  {
2
2
  "name": "@ktjs/core",
3
- "version": "0.7.1",
4
- "description": "Core functionality for kt.js - DOM manipulation utilities",
3
+ "version": "0.8.0",
4
+ "description": "Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.mjs",
11
- "default": "./dist/index.mjs"
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "./jsx": {
15
+ "types": "./dist/jsx/index.d.ts",
16
+ "import": "./dist/jsx/index.mjs"
17
+ },
18
+ "./jsx-runtime": {
19
+ "types": "./dist/jsx/jsx-runtime.d.ts",
20
+ "import": "./dist/jsx/jsx-runtime.mjs"
21
+ },
22
+ "./jsx-dev-runtime": {
23
+ "types": "./dist/jsx/jsx-runtime.d.ts",
24
+ "import": "./dist/jsx/jsx-runtime.mjs"
25
+ }
12
26
  },
13
27
  "files": [
14
28
  "dist"