kt.js 0.19.0 → 0.19.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/README.md CHANGED
@@ -1,376 +1,453 @@
1
1
  <img src="https://raw.githubusercontent.com/baendlorel/kt.js/dev/.assets/ktjs-0.0.1.svg" alt="KT.js Logo" width="150"/>
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@ktjs/core.svg)](https://www.npmjs.com/package/@ktjs/core)
3
+ [![npm version](https://img.shields.io/npm/v/kt.js.svg)](https://www.npmjs.com/package/kt.js) [![license](https://img.shields.io/github/license/baendlorel/kt.js.svg)](https://github.com/baendlorel/kt.js/blob/main/LICENSE)
4
4
 
5
- > 📦 Part of [KT.js](https://github.com/baendlorel/kt.js) - A simple and easy-to-use web framework that never re-renders.
5
+ [CHANGLOG✨](CHANGELOG.md)
6
6
 
7
- Core DOM manipulation utilities for KT.js framework with built-in JSX/TSX support.
7
+ ## What's New (v0.19.x)
8
8
 
9
- ## Overview
9
+ - Release `0.19.0` (2026-01-31): build & packaging fixes, TypeScript and lint cleanups, MUI-focused fixes (JSX handling, `jsxImportSource` set to `@ktjs/core`, radio/checkbox/TextField fixes), and repo cleanup (removed alias detection, moved shared utilities into `shared`). See the full details in the CHANGELOG.
10
10
 
11
- `@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.
11
+ > Note: This framework is still under development. APIs, type declarations, and other parts **may change frequently**. If you use it, please watch for updates in the near future. Feel free to mail me if you have any questions!
12
12
 
13
- **Current Version:** 0.18.1
13
+ KT.js is a tiny DOM utility focused on direct DOM manipulation. It favors not forcing re-renders and aims to keep DOM updates to the absolute minimum for maximum performance.
14
14
 
15
- ## Features
15
+ For more awesome packages, check out [my homepage💛](https://baendlorel.github.io/?repoType=npm)
16
16
 
17
- - **`h` Function**: Create HTMLElements with a simple, flexible API
18
- - Support for attributes, content, and event handlers
19
- - `on:<eventName>` syntax for event handlers (e.g., `on:click`)
20
- - Function attributes automatically treated as event listeners
21
- - Full TypeScript support with intelligent type inference
22
- - **JSX/TSX Support**: Built-in JSX runtime (no separate package needed)
23
- - Zero virtual DOM - JSX compiles directly to `h()` function calls
24
- - Full HTML element type inference (`<button>` returns `HTMLButtonElement`)
25
- - Support for function components
26
- - `redraw()` method for controlled re-rendering
27
- - **k-if directive**: Conditional element creation with `k-if` attribute
28
- - Array children support for seamless list rendering
29
- - **KTFor Component**: Efficient list rendering with key-based optimization (v0.16.0)
30
- - Returns Comment anchor with `__kt_for_list__` array storing rendered elements
31
- - Auto-appends list items when anchor is added via `applyContent`
32
- - Key-based DOM reuse with customizable key function (default: identity)
33
- - Type-safe with full TypeScript generics support
34
- - **KTAsync Component**: Handle async components with ease
35
- - Automatic handling of Promise-based components
36
- - Seamless integration with JSX/TSX
37
- - Fallback placeholder during async loading
38
- - Type-safe async component support
39
- - **Redraw Mechanism**: Fine-grained control over component updates
40
- - Update props and children selectively
41
- - Efficient replacement strategy
42
- - Works with both native elements and function components
43
- - **Ref Enhancement**: Change event binding support for `ref` (v0.18.1)
44
- - New methods `addOnChange` and `removeOnChange` for listening to value changes
45
- - Automatically calls registered callbacks when `ref.value` is updated
46
- - When both old and new values are DOM nodes, automatically replaces old node with new one in the DOM
47
- - **DOM Utilities**: Helper functions for common DOM operations
48
- - Native method caching for performance
49
- - Symbol-based private properties for internal state
50
- - **Type-Safe**: Complete TypeScript definitions
51
- - Accurate HTMLElement type inference
52
- - Event handler type hints with proper event types
53
- - Support for custom attributes and properties
54
- - **ES5 Compatible**: Transpiled to ES5 for maximum browser compatibility
55
- - **Zero Dependencies**: Fully self-contained implementation
56
-
57
- ## Installation
17
+ ## Architecture
18
+
19
+ KT.js is now a **monorepo** containing multiple packages:
20
+
21
+ - **[kt.js](./packages/kt.js)**: Main entry package that re-exports all functionality
22
+ - **[@ktjs/core](./packages/core)**: Core DOM manipulation utilities and the `h` function. SX/TSX support with full TypeScript integration (included in kt.js package)
23
+ - **[@ktjs/router](./packages/router)**: Client-side routing with navigation guards (not included in kt.js package)
24
+ - **[@ktjs/shortcuts](./packages/shortcuts)**: Convenient shortcut functions for common operations
25
+
26
+ You can install the full package or individual packages as needed:
58
27
 
59
28
  ```bash
60
- pnpm add @ktjs/core
61
- ```
29
+ # Install the main package (includes core + jsx + shortcuts)
30
+ pnpm add kt.js
62
31
 
63
- ## Usage
32
+ # Or install individual packages
33
+ pnpm add @ktjs/core # Core DOM utilities (independent)
34
+ pnpm add @ktjs/router # Client-side router (independent)
35
+ pnpm add @ktjs/shortcuts # Shortcuts (requires @ktjs/core)
36
+ ```
64
37
 
65
- ### Basic Element Creation
38
+ ## Philosophy
66
39
 
67
- ```typescript
68
- import { h } from '@ktjs/core';
40
+ As a web framework, repeatedly creating a large number of variables and objects is unacceptable. So I created KT.js.
69
41
 
70
- // Simple element
71
- const div = h('div', { class: 'container' }, 'Hello World');
42
+ KT.js follows one rule: **full control of DOM and avoid unnecessary repainting**.
72
43
 
73
- // With multiple attributes
74
- const input = h('input', {
75
- type: 'text',
76
- placeholder: 'Enter text',
77
- value: 'initial',
78
- });
44
+ ## Key Features
79
45
 
80
- // Nested elements
81
- const card = h('div', { class: 'card' }, [
82
- h('h2', {}, 'Title'),
83
- h('p', {}, 'Description'),
84
- h('button', {}, 'Click me'),
85
- ]);
46
+ - **Monorepo Architecture**: Modular packages that can be installed independently or together
47
+ - **Tiny Bundle Size**: Minimal runtime overhead with aggressive tree-shaking
48
+ - **`h` function**: Create DOM elements with a simple, flexible API
49
+ - Shortcut functions for all HTML elements (`div`, `span`, `button`, etc.)
50
+ - Event handlers with `on:<eventName>` syntax or function attributes
51
+ - Full TypeScript support with intelligent type inference
52
+ - **JSX/TSX Support**: Full JSX syntax support with TypeScript integration
53
+ - Zero virtual DOM - JSX compiles directly to `h()` function calls
54
+ - Full HTML element type inference (`<button>` returns `HTMLButtonElement`)
55
+ - Support for `on:click` event handler syntax
56
+ - `redraw()` method for controlled component updates (v0.11+)
57
+ - `k-if` directive for conditional rendering (v0.14.6+)
58
+ - Array children support for seamless `.map()` integration (v0.14.1+)
59
+ - **List Rendering**: Efficient list rendering with `KTFor` component (v0.16.0+)
60
+ - Comment anchor with `__kt_for_list__` array property
61
+ - Key-based DOM reuse for minimal updates
62
+ - Auto-appends list items when anchor added to parent
63
+ - **Async Components**: Built-in support for Promise-based components
64
+ - `KTAsync` component for handling async operations
65
+ - Automatic placeholder management during loading
66
+ - Seamless integration with JSX/TSX syntax
67
+ - **Client-Side Router** (separate package):
68
+ - Hash-based routing only (simplified from v0.14.7+)
69
+ - Async navigation guards with Promise support
70
+ - Dynamic route parameters and query string parsing
71
+ - RouterView component for declarative routing
72
+ - Pure routing logic - no rendering, no dependencies
73
+ - **Shortcuts & Utilities**:
74
+ - `withDefaults`: Wrap element creation functions with default properties
75
+ - Convenient shorthand functions for common operations
76
+ - Form helpers and layout utilities
77
+ - **Full ES5 Compatibility**: Works in IE9+ and all modern browsers
78
+ - Transpiled to ES5 with no modern syntax
79
+ - Optional minimal Promise polyfill for older environments
80
+ - **Shared Runtime**: Efficient code sharing across packages with zero overhead
81
+
82
+ ## Getting started
83
+
84
+ Install via package managers:
86
85
 
87
- // Note: attr parameter must be an object
88
- // String className shorthand is NOT supported:
89
- // h('div', 'my-class') ❌ - This will throw an error
86
+ ```bash
87
+ npm install kt.js
88
+ # or
89
+ pnpm add kt.js
90
90
  ```
91
91
 
92
- ### Event Handlers
93
-
94
- ```typescript
95
- import { h } from '@ktjs/core';
92
+ ```ts
93
+ import { h, div } from 'kt.js';
96
94
 
97
- // on: prefixed attribute (event handler)
98
- const button1 = h(
99
- 'button',
100
- {
101
- 'on:click': () => alert('Clicked!'),
102
- },
103
- 'Button 1',
104
- );
95
+ const container = div('container', [div('header'), div('body', 'something'), div('footer')]);
96
+ const app = h('section', { id: 'app' }, container);
97
+ ```
105
98
 
106
- // Function attribute (also treated as event listener)
107
- const button2 = h(
108
- 'button',
109
- {
110
- click: (e) => console.log('Event:', e),
111
- 'data-id': '123', // Regular attribute
112
- },
113
- 'Button 2',
114
- );
99
+ This will create the following DOM structure:
115
100
 
116
- // Both regular and event handler for same name
117
- const input = h('input', {
118
- value: 'initial', // Regular attribute
119
- 'on:change': (e) => console.log('Changed'), // Event listener
120
- });
101
+ ```html
102
+ <section id="app">
103
+ <div class="container">
104
+ <div class="header"></div>
105
+ <div class="body">something</div>
106
+ <div class="footer"></div>
107
+ </div>
108
+ </section>
121
109
  ```
122
110
 
123
- ### JSX/TSX Support
111
+ ### Using JSX/TSX
124
112
 
125
- ```tsx
126
- import { h } from '@ktjs/core';
113
+ KT.js now has full JSX support! With the `@ktjs/jsx` package (included in the main `kt.js` package), you can write components using familiar JSX syntax:
114
+
115
+ **TypeScript Configuration** (`tsconfig.json`):
127
116
 
128
- // Configure tsconfig.json
117
+ ```json
129
118
  {
130
119
  "compilerOptions": {
131
120
  "jsx": "react-jsx",
132
- "jsxImportSource": "@ktjs/core"
121
+ "jsxImportSource": "kt.js"
133
122
  }
134
123
  }
135
-
136
- // Use JSX syntax
137
- const App = () => (
138
- <div class="app">
139
- <h1>Hello KT.js</h1>
140
- <button on:click={() => alert('Hi')}>Click me</button>
141
- </div>
142
- );
143
-
144
- // Function components
145
- const Greeting = ({ name }: { name: string }) => (
146
- <div class="greeting">Hello, {name}!</div>
147
- );
148
-
149
- const app = <Greeting name="World" />;
150
124
  ```
151
125
 
152
- ### Conditional Rendering with k-if (v0.14.6+)
153
-
154
- The `k-if` directive allows conditional element creation:
126
+ **Basic JSX Example**:
155
127
 
156
128
  ```tsx
157
- import { h } from '@ktjs/core';
129
+ import { jsx } from 'kt.js';
158
130
 
159
- // Element will only be created if condition is true
160
- const isVisible = true;
161
- const element = <div k-if={isVisible}>This will be rendered</div>;
131
+ function Counter() {
132
+ const count = 0;
162
133
 
163
- // Element will not be created if condition is false
164
- const isHidden = false;
165
- const hidden = <div k-if={isHidden}>This will NOT be rendered</div>;
166
- // hidden will be undefined/null
167
-
168
- // Practical example
169
- const UserProfile = ({ user, isLoggedIn }: { user: any; isLoggedIn: boolean }) => (
170
- <div>
171
- <h1>User Profile</h1>
172
- <div k-if={isLoggedIn}>
173
- <p>Welcome, {user.name}!</p>
174
- <button>Logout</button>
175
- </div>
176
- <div k-if={!isLoggedIn}>
177
- <p>Please log in to continue</p>
178
- <button>Login</button>
134
+ return (
135
+ <div class="counter">
136
+ <h1>Counter: {count}</h1>
137
+ <button on:click={() => console.log('Clicked!')}>Increment</button>
179
138
  </div>
180
- </div>
181
- );
182
- ```
183
-
184
- **Note**: `k-if` is evaluated **once** at element creation time. It's not reactive - if you need dynamic visibility, use CSS or manually recreate the element.
139
+ );
140
+ }
185
141
 
186
- ### Redraw Mechanism (v0.11+)
142
+ // JSX compiles to direct h() function calls - no virtual DOM!
143
+ const counterElement = <Counter />;
144
+ ```
187
145
 
188
- The `redraw()` method allows you to update components efficiently:
146
+ **Event Handling with @ Syntax**:
189
147
 
190
148
  ```tsx
191
- import { h, KTHTMLElement } from '@ktjs/core';
149
+ function App() {
150
+ const handleClick = () => alert('Button clicked!');
192
151
 
193
- // With JSX - get element with redraw method
194
- const counter = (<button on:click={() => counter.redraw({ count: count + 1 })}>Count: {0}</button>) as KTHTMLElement;
152
+ return (
153
+ <div>
154
+ <button on:click={handleClick}>Click me</button>
155
+ </div>
156
+ );
157
+ }
158
+ ```
195
159
 
196
- // Function component with redraw
197
- const Counter = ({ count = 0 }: { count?: number }) => (
198
- <div>
199
- <div>Count: {count}</div>
200
- <button on:click={() => element.redraw({ count: count + 1 })}>Increment</button>
201
- </div>
202
- );
160
+ **Type Safety**:
203
161
 
204
- const element = (<Counter />) as KTHTMLElement;
162
+ ```tsx
163
+ // TypeScript knows this is an HTMLButtonElement
164
+ const button: HTMLButtonElement = <button>Click</button>;
205
165
 
206
- // Update props manually
207
- element.redraw({ count: 10 });
166
+ // TypeScript knows this is an HTMLInputElement
167
+ const input: HTMLInputElement = <input type="text" value="hello" />;
208
168
 
209
- // Update children (for native elements)
210
- const div = (<div>Old content</div>) as KTHTMLElement;
211
- div.redraw(undefined, 'New content');
169
+ // TypeScript provides autocomplete for HTML attributes
170
+ const div: HTMLDivElement = <div className="container" id="main" />;
212
171
  ```
213
172
 
214
- ### List Rendering with KTFor (v0.16.0)
173
+ **Important Notes**:
215
174
 
216
- The `KTFor` component provides efficient list rendering with key-based DOM reuse:
175
+ - KT.js JSX has **no Fragment support** - we don't have a Fragment concept
176
+ - JSX compiles directly to `h()` function calls - **zero virtual DOM overhead**
177
+ - Use `on:click` syntax for event handlers to avoid conflicts with existing attributes
178
+ - All JSX elements have proper HTML element type inference in TypeScript
179
+ - Use `k-if` attribute for conditional rendering (v0.14.6+)
180
+ - Children can be arrays for easy `.map()` integration (v0.14.1+)
217
181
 
218
- ```tsx
219
- import { KTFor } from '@ktjs/core';
182
+ **Conditional Rendering with k-if** (v0.14.6+):
220
183
 
221
- interface Todo {
222
- id: number;
223
- text: string;
224
- done: boolean;
184
+ ```tsx
185
+ import { jsx } from 'kt.js';
186
+
187
+ function UserProfile({ user, isLoggedIn }: { user: any; isLoggedIn: boolean }) {
188
+ return (
189
+ <div>
190
+ <h1>Profile</h1>
191
+ {/* Element only created if condition is true */}
192
+ <div k-if={isLoggedIn}>
193
+ <p>Welcome, {user.name}!</p>
194
+ <button>Logout</button>
195
+ </div>
196
+ {/* Element only created if condition is true */}
197
+ <div k-if={!isLoggedIn}>
198
+ <p>Please log in</p>
199
+ <button>Login</button>
200
+ </div>
201
+ </div>
202
+ );
225
203
  }
204
+ ```
226
205
 
227
- let todos: Todo[] = [
228
- { id: 1, text: 'Buy milk', done: false },
229
- { id: 2, text: 'Write code', done: true },
230
- ];
231
-
232
- // Create optimized list with key-based reuse
233
- const todoList = (
234
- <KTFor
235
- list={todos}
236
- key={(item) => item.id} // Optional, defaults to identity function
237
- map={(item, index) => (
238
- <div class={`todo ${item.done ? 'done' : ''}`}>
239
- <input type="checkbox" checked={item.done} />
240
- <span>{item.text}</span>
241
- <button on:click={() => deleteTodo(item.id)}>Delete</button>
242
- </div>
243
- )}
244
- />
245
- );
206
+ **Array Children Support** (v0.14.1+):
246
207
 
247
- // Add to DOM - anchor comment + __kt_for_list__ items are appended
248
- document.body.appendChild(todoList);
208
+ ```tsx
209
+ import { jsx } from 'kt.js';
210
+
211
+ function TodoList({ todos }: { todos: string[] }) {
212
+ return (
213
+ <div>
214
+ <h2>Todo List</h2>
215
+ <ul>
216
+ {/* Map arrays directly as children */}
217
+ {todos.map((todo) => (
218
+ <li>{todo}</li>
219
+ ))}
220
+ </ul>
221
+ </div>
222
+ );
223
+ }
249
224
 
250
- // Update the list - only changed items are updated
251
- todos = [...todos, { id: 3, text: 'New task', done: false }];
252
- todoList.redraw({ list: todos });
225
+ // Mix mapped elements with other elements
226
+ function MixedList({ items }: { items: string[] }) {
227
+ return (
228
+ <ul>
229
+ <li>Header Item</li>
230
+ {items.map((item) => (
231
+ <li>{item}</li>
232
+ ))}
233
+ <li>Footer Item</li>
234
+ </ul>
235
+ );
236
+ }
253
237
  ```
254
238
 
255
- **How it works:**
239
+ ### Async Components with KTAsync
256
240
 
257
- - Returns Comment anchor (`<!-- kt-for -->`) with `__kt_for_list__` array property
258
- - When appended via `applyContent`, anchor and all list items are added to DOM
259
- - Uses key-based diff to reuse DOM nodes on `redraw()`
260
- - Only adds/removes/moves nodes that changed
241
+ KT.js provides built-in support for async components through the `KTAsync` component:
261
242
 
262
- ````
243
+ ```tsx
244
+ import { KTAsync, ref } from 'kt.js';
245
+
246
+ // Define an async component that returns a Promise<HTMLElement>
247
+ const AsyncUserCard = function () {
248
+ return fetch('/api/user')
249
+ .then((res) => res.json())
250
+ .then((user) => (
251
+ <div class="user-card">
252
+ <h2>{user.name}</h2>
253
+ <p>{user.email}</p>
254
+ </div>
255
+ ));
256
+ };
263
257
 
264
- ### Array Children Support (v0.14.1+)
258
+ // Use KTAsync to handle the async component
259
+ function App() {
260
+ return (
261
+ <div class="app">
262
+ <h1>User Profile</h1>
263
+ <KTAsync component={AsyncUserCard} />
264
+ </div>
265
+ );
266
+ }
265
267
 
266
- Children can now be arrays for easier list rendering:
268
+ // The component starts with a placeholder comment node
269
+ // When the Promise resolves, it automatically replaces with the actual element
270
+ ```
267
271
 
268
- ```tsx
269
- import { h } from '@ktjs/core';
270
-
271
- // Map arrays directly as children
272
- const items = ['Apple', 'Banana', 'Orange'];
273
- const list = (
274
- <ul>
275
- {items.map((item) => (
276
- <li>{item}</li>
277
- ))}
278
- </ul>
279
- );
272
+ **How KTAsync works:**
280
273
 
281
- // Mix mapped elements with other elements
282
- const TodoList = ({ todos }: { todos: string[] }) => (
283
- <div>
284
- <h2>Todo List</h2>
285
- <ul>
286
- {todos.map((todo) => (
287
- <li>{todo}</li>
288
- ))}
289
- <li>
290
- <button>Add More</button>
291
- </li>
292
- </ul>
293
- </div>
294
- );
295
- ````
274
+ 1. Creates a placeholder comment node (`ktjs-suspense-placeholder`) immediately
275
+ 2. Calls your component function (which should return a `Promise<HTMLElement>` or `HTMLElement`)
276
+ 3. When the Promise resolves, automatically replaces the placeholder with the resolved element
277
+ 4. If your component returns a non-Promise value, it's used directly without async handling
296
278
 
297
- ### Async Components
279
+ **Example with dynamic updates:**
298
280
 
299
- ```typescript
300
- import { KTAsync, h } from '@ktjs/core';
281
+ ```tsx
282
+ const DynamicContent = function () {
283
+ const count = ref(0);
284
+ const container = (
285
+ <div>
286
+ <p>Count: {count}</p>
287
+ <button on:click={() => count.value++}>Increment</button>
288
+ </div>
289
+ );
301
290
 
302
- // Define an async component that returns a Promise
303
- const AsyncComponent = () => {
291
+ // Simulate async data loading
304
292
  return new Promise<HTMLElement>((resolve) => {
305
- setTimeout(() => {
306
- const element = h('div', { class: 'loaded' }, 'Content loaded!');
307
- resolve(element);
308
- }, 1000);
293
+ setTimeout(() => resolve(container), 500);
309
294
  });
310
295
  };
311
296
 
312
- // Use KTAsync to handle the async component
313
- const container = h('div', {}, [
314
- h('h1', {}, 'Loading...'),
315
- KTAsync({ component: AsyncComponent }),
316
- ]);
317
-
318
- // With JSX/TSX
319
- const App = () => (
297
+ // Usage
298
+ const app = (
320
299
  <div>
321
- <h1>Loading...</h1>
322
- <KTAsync component={AsyncComponent} />
300
+ <h1>Loading async content...</h1>
301
+ <KTAsync component={DynamicContent} />
323
302
  </div>
324
303
  );
304
+ ```
325
305
 
326
- // With custom placeholder
327
- const AppWithSkeleton = () => (
328
- <div>
329
- <KTAsync
330
- component={AsyncComponent}
331
- skeleton={<div class="skeleton">Loading...</div>}
332
- />
333
- </div>
306
+ If you give a function in attributes, it will be treated as an event listener, and the key will be considered as the event name. `@<eventName>` will also be considered as the handler to avoid conflicts with existing attributes:
307
+
308
+ ```ts
309
+ const button = btn(
310
+ {
311
+ dblclick: '22',
312
+ 'on:dblclick': function trueHandler() {
313
+ /* ... */
314
+ },
315
+ },
316
+ 'Click me',
334
317
  );
318
+
319
+ // This is equivalent to:
320
+ const button = btn(undefined, 'Click me');
321
+ button.setAttribute('dblclick', '22');
322
+ button.addEventListener('click', () => alert('Clicked!'));
323
+ button.addEventListener('dblclick', function trueHandler() {
324
+ /* ... */
325
+ });
335
326
  ```
336
327
 
337
- **How it works:**
328
+ ### Working with CSS-in-JS Libraries
338
329
 
339
- - `KTAsync` creates a placeholder (comment node or custom skeleton) immediately
340
- - When the Promise resolves, it automatically replaces the placeholder with the actual element
341
- - If the component returns a non-Promise value, it's used directly
342
- - No manual DOM manipulation needed - just return a Promise from your component
330
+ KT.js works seamlessly with CSS-in-JS libraries like `@emotion/css`:
343
331
 
344
- ## API Reference
332
+ ```ts
333
+ import { css } from '@emotion/css';
334
+ import { h, div } from 'kt.js';
345
335
 
346
- ### `h(tag, attributes?, content?)`
336
+ const className = css`
337
+ color: red;
338
+ font-size: 20px;
339
+ `;
347
340
 
348
- Creates an HTMLElement with the specified tag, attributes, and content.
341
+ // Pass class name as attribute
342
+ h('div', { class: className }, 'Styled text');
349
343
 
350
- **Parameters:**
344
+ // Or as the first string argument
345
+ div(className, 'Styled text');
346
+ ```
351
347
 
352
- - `tag` (string): HTML tag name (e.g., 'div', 'span', 'button')
353
- - `attributes` (object, optional): Element attributes and event handlers. **Must be an object** - string className shorthand is not supported.
354
- - `content` (string | HTMLElement | Array, optional): Element content
348
+ ### Using Shortcuts with Default Values
355
349
 
356
- **Returns:** HTMLElement
350
+ The `withDefaults` function allows you to create element factories with predefined properties:
357
351
 
358
- ## Type System
352
+ ```ts
353
+ import { withDefaults, div, button } from 'kt.js';
359
354
 
360
- The package includes comprehensive TypeScript definitions:
355
+ // Create a styled div factory
356
+ const card = withDefaults(div, { class: 'card' });
357
+ const blueCard = withDefaults(card, { style: 'background: blue' });
361
358
 
362
- - `HTMLTag`: Union type of all valid HTML tag names
363
- - `KTAttribute`: Attribute object type for element attributes and event handlers
364
- - `KTRawAttr`: Union type for raw attribute parameter (`KTAttribute | null | undefined | '' | false`)
365
- - `KTRawContent`: Valid content types (string, Element, Array, Promise, etc.)
366
- - Event handler types with proper event object types
359
+ // Use them
360
+ const myCard = card('card-body', 'Content'); // <div class="card"><div class="card-body">Content</div></div>
361
+ const myBlueCard = blueCard('title', 'Blue!'); // <div class="card" style="background: blue"><div class="title">Blue!</div></div>
362
+ ```
367
363
 
368
- ## Performance Considerations
364
+ ## Router
365
+
366
+ The router is available as a separate package `@ktjs/router`:
367
+
368
+ ```ts
369
+ import { createRouter } from '@ktjs/router';
370
+ import { div, h1 } from 'kt.js';
371
+
372
+ const router = createRouter({
373
+ routes: [
374
+ {
375
+ path: '/',
376
+ name: 'home',
377
+ beforeEnter: (to) => {
378
+ // Render your page here
379
+ document.getElementById('app')!.innerHTML = '';
380
+ document.getElementById('app')!.appendChild(div({}, [h1({}, 'Home Page')]));
381
+ },
382
+ },
383
+ {
384
+ path: '/user/:id',
385
+ name: 'user',
386
+ beforeEnter: (to) => {
387
+ // Route-specific guard and rendering
388
+ console.log('Entering user page');
389
+ document.getElementById('app')!.innerHTML = '';
390
+ document.getElementById('app')!.appendChild(div({}, [h1({}, `User ${to.params.id}`)]));
391
+ return true;
392
+ },
393
+ },
394
+ ],
395
+ beforeEach: async (to, from) => {
396
+ // Global navigation guard - return false to block navigation
397
+ console.log('Navigating to:', to.path);
398
+ return true;
399
+ },
400
+ afterEach: (to) => {
401
+ // Called after successful navigation
402
+ document.title = to.name || to.path;
403
+ },
404
+ onError: (error) => {
405
+ console.error('Router error:', error);
406
+ },
407
+ });
408
+
409
+ // Navigate programmatically
410
+ router.push('/user/123');
411
+ router.push('/user/456?page=2');
412
+
413
+ // Navigate by route name
414
+ router.push({ name: 'user', params: { id: '789' } });
415
+
416
+ // Get current route
417
+ console.log(router.current?.path, router.current?.params, router.current?.query);
418
+ ```
419
+
420
+ ### Router Features
369
421
 
370
- - Native DOM methods are cached for repeated use
371
- - Symbol-based properties avoid prototype pollution
372
- - Minimal object creation in hot paths
373
- - Tree-shakeable - only import what you use
422
+ - **Hash-based Routing Only** (v0.14.7+): Uses URL hash for client-side navigation (`#/path`)
423
+ - **Dynamic Parameters**: Support for dynamic route segments (`/user/:id`)
424
+ - **Query Strings**: Automatic parsing of query parameters (`?key=value`)
425
+ - **Named Routes**: Navigate using route names instead of paths
426
+ - **Async Navigation Guards**:
427
+ - `beforeEach`: Global guard before navigation (async)
428
+ - `beforeEnter`: Per-route guard (can also be used for rendering, async)
429
+ - `afterEach`: Global hook after navigation
430
+ - All guards support Promise-based async operations
431
+ - Guards can return `false` to cancel, string/object to redirect
432
+ - `GuardLevel` for fine-grained control over guard execution
433
+ - **Error Handling**: `onError` and `onNotFound` callbacks
434
+ - **Optimized Performance**: Pre-flattened routes and efficient matching algorithm
435
+ - **Zero Dependencies**: Fully self-contained router implementation (does not require `@ktjs/core` for runtime, only for TypeScript types)
436
+ - **Pure Routing**: No rendering logic - you control the DOM
437
+ - **Automatic Initialization**: Router auto-initializes on creation (v0.14.7+)
438
+
439
+ ## Browser Compatibility
440
+
441
+ KT.js is transpiled to ES5 and works in all modern browsers as well as legacy browsers including IE9+.
442
+
443
+ ### Promise Polyfill
444
+
445
+ For environments without native `Promise` support (like IE).
446
+
447
+ ```js
448
+ import 'some promise polyfill'; // Will fallback to sync version if Promise is not available
449
+ import { h, div, createRouter } from 'kt.js';
450
+ ```
374
451
 
375
452
  ## License
376
453
 
@@ -200,7 +200,7 @@ const svgTempWrapper = document.createElement('div');
200
200
  * ## About
201
201
  * @package @ktjs/core
202
202
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
203
- * @version 0.19.0 (Last Update: 2026.01.31 22:50:55.987)
203
+ * @version 0.19.1 (Last Update: 2026.01.31 23:07:55.249)
204
204
  * @license MIT
205
205
  * @link https://github.com/baendlorel/kt.js
206
206
  * @link https://baendlorel.github.io/ Welcome to my site!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kt.js",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "author": {
5
5
  "name": "Kasukabe Tsumugi",
6
6
  "email": "futami16237@gmail.com"
@@ -41,7 +41,7 @@
41
41
  ],
42
42
  "license": "MIT",
43
43
  "dependencies": {
44
- "@ktjs/core": "0.19.0"
44
+ "@ktjs/core": "0.19.1"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "rollup -c rollup.config.mjs",