@ktjs/core 0.20.3 → 0.21.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 +1 -453
- package/dist/index.d.ts +33 -4
- package/dist/index.iife.js +68 -25
- package/dist/index.legacy.js +68 -26
- package/dist/index.mjs +67 -26
- package/dist/jsx/index.d.ts +33 -3
- package/dist/jsx/index.mjs +67 -26
- package/dist/jsx/jsx-runtime.d.ts +16 -2
- package/dist/jsx/jsx-runtime.mjs +41 -25
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,453 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/kt.js) [](https://github.com/baendlorel/kt.js/blob/main/LICENSE)
|
|
4
|
-
|
|
5
|
-
[CHANGLOG✨](CHANGELOG.md)
|
|
6
|
-
|
|
7
|
-
## What's New (v0.19.x)
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
For more awesome packages, check out [my homepage💛](https://baendlorel.github.io/?repoType=npm)
|
|
16
|
-
|
|
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
|
-
|
|
25
|
-
You can install the full package or individual packages as needed:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pnpm add kt.js
|
|
29
|
-
|
|
30
|
-
# Or install individual packages
|
|
31
|
-
pnpm add @ktjs/core # Core DOM utilities (independent)
|
|
32
|
-
pnpm add @ktjs/router # Client-side router (requires @ktjs/core)
|
|
33
|
-
pnpm add @ktjs/mui # Material UI components (requires @ktjs/core)
|
|
34
|
-
pnpm add @ktjs/shortcuts # Shortcuts (requires @ktjs/core)
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Philosophy
|
|
38
|
-
|
|
39
|
-
As a web framework, repeatedly creating a large number of variables and objects is unacceptable. So I created KT.js.
|
|
40
|
-
|
|
41
|
-
KT.js follows one rule: **full control of DOM and avoid unnecessary repainting**.
|
|
42
|
-
|
|
43
|
-
## Key Features
|
|
44
|
-
|
|
45
|
-
- **Monorepo Architecture**: Modular packages that can be installed independently or together
|
|
46
|
-
- **Tiny Bundle Size**: Minimal runtime overhead with aggressive tree-shaking
|
|
47
|
-
- **`h` function**: Create DOM elements with a simple, flexible API
|
|
48
|
-
- Shortcut functions for all HTML elements (`div`, `span`, `button`, etc.)
|
|
49
|
-
- Event handlers with `on:<eventName>` syntax or function attributes
|
|
50
|
-
- Full TypeScript support with intelligent type inference
|
|
51
|
-
- **JSX/TSX Support**: Full JSX syntax support with TypeScript integration
|
|
52
|
-
- Zero virtual DOM - JSX compiles directly to `h()` function calls
|
|
53
|
-
- Full HTML element type inference (`<button>` returns `HTMLButtonElement`)
|
|
54
|
-
- Support for `on:click` event handler syntax
|
|
55
|
-
- `redraw()` method for controlled component updates (v0.11+)
|
|
56
|
-
- `k-if` directive for conditional rendering (v0.14.6+)
|
|
57
|
-
- Array children support for seamless `.map()` integration (v0.14.1+)
|
|
58
|
-
- **List Rendering**: Efficient list rendering with `KTFor` component (v0.16.0+)
|
|
59
|
-
- Comment anchor with `__kt_for_list__` array property
|
|
60
|
-
- Key-based DOM reuse for minimal updates
|
|
61
|
-
- Auto-appends list items when anchor added to parent
|
|
62
|
-
- **Async Components**: Built-in support for Promise-based components
|
|
63
|
-
- `KTAsync` component for handling async operations
|
|
64
|
-
- Automatic placeholder management during loading
|
|
65
|
-
- Seamless integration with JSX/TSX syntax
|
|
66
|
-
- **Client-Side Router** (separate package):
|
|
67
|
-
- Hash-based routing only (simplified from v0.14.7+)
|
|
68
|
-
- Async navigation guards with Promise support
|
|
69
|
-
- Dynamic route parameters and query string parsing
|
|
70
|
-
- RouterView component for declarative routing
|
|
71
|
-
- Pure routing logic - no rendering, no dependencies
|
|
72
|
-
- **Shortcuts & Utilities**:
|
|
73
|
-
- `withDefaults`: Wrap element creation functions with default properties
|
|
74
|
-
- Convenient shorthand functions for common operations
|
|
75
|
-
- Form helpers and layout utilities
|
|
76
|
-
- **Full ES5 Compatibility**: Works in IE9+ and all modern browsers
|
|
77
|
-
- Transpiled to ES5 with no modern syntax
|
|
78
|
-
- Optional minimal Promise polyfill for older environments
|
|
79
|
-
- **Shared Runtime**: Efficient code sharing across packages with zero overhead
|
|
80
|
-
|
|
81
|
-
## Getting started
|
|
82
|
-
|
|
83
|
-
Install via package managers:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npm install kt.js
|
|
87
|
-
# or
|
|
88
|
-
pnpm add kt.js
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import { h, div } from 'kt.js';
|
|
93
|
-
|
|
94
|
-
const container = div('container', [div('header'), div('body', 'something'), div('footer')]);
|
|
95
|
-
const app = h('section', { id: 'app' }, container);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
This will create the following DOM structure:
|
|
99
|
-
|
|
100
|
-
```html
|
|
101
|
-
<section id="app">
|
|
102
|
-
<div class="container">
|
|
103
|
-
<div class="header"></div>
|
|
104
|
-
<div class="body">something</div>
|
|
105
|
-
<div class="footer"></div>
|
|
106
|
-
</div>
|
|
107
|
-
</section>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Using JSX/TSX
|
|
111
|
-
|
|
112
|
-
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:
|
|
113
|
-
|
|
114
|
-
**TypeScript Configuration** (`tsconfig.json`):
|
|
115
|
-
|
|
116
|
-
```json
|
|
117
|
-
{
|
|
118
|
-
"compilerOptions": {
|
|
119
|
-
"jsx": "react-jsx",
|
|
120
|
-
"jsxImportSource": "kt.js"
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Basic JSX Example**:
|
|
126
|
-
|
|
127
|
-
```tsx
|
|
128
|
-
import { jsx } from 'kt.js';
|
|
129
|
-
|
|
130
|
-
function Counter() {
|
|
131
|
-
const count = 0;
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<div class="counter">
|
|
135
|
-
<h1>Counter: {count}</h1>
|
|
136
|
-
<button on:click={() => console.log('Clicked!')}>Increment</button>
|
|
137
|
-
</div>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// JSX compiles to direct h() function calls - no virtual DOM!
|
|
142
|
-
const counterElement = <Counter />;
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**Event Handling with @ Syntax**:
|
|
146
|
-
|
|
147
|
-
```tsx
|
|
148
|
-
function App() {
|
|
149
|
-
const handleClick = () => alert('Button clicked!');
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<div>
|
|
153
|
-
<button on:click={handleClick}>Click me</button>
|
|
154
|
-
</div>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
**Type Safety**:
|
|
160
|
-
|
|
161
|
-
```tsx
|
|
162
|
-
// TypeScript knows this is an HTMLButtonElement
|
|
163
|
-
const button: HTMLButtonElement = <button>Click</button>;
|
|
164
|
-
|
|
165
|
-
// TypeScript knows this is an HTMLInputElement
|
|
166
|
-
const input: HTMLInputElement = <input type="text" value="hello" />;
|
|
167
|
-
|
|
168
|
-
// TypeScript provides autocomplete for HTML attributes
|
|
169
|
-
const div: HTMLDivElement = <div className="container" id="main" />;
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
**Important Notes**:
|
|
173
|
-
|
|
174
|
-
- KT.js JSX has **no Fragment support** - we don't have a Fragment concept
|
|
175
|
-
- JSX compiles directly to `h()` function calls - **zero virtual DOM overhead**
|
|
176
|
-
- Use `on:click` syntax for event handlers to avoid conflicts with existing attributes
|
|
177
|
-
- All JSX elements have proper HTML element type inference in TypeScript
|
|
178
|
-
- Use `k-if` attribute for conditional rendering (v0.14.6+)
|
|
179
|
-
- Children can be arrays for easy `.map()` integration (v0.14.1+)
|
|
180
|
-
|
|
181
|
-
**Conditional Rendering with k-if** (v0.14.6+):
|
|
182
|
-
|
|
183
|
-
```tsx
|
|
184
|
-
import { jsx } from 'kt.js';
|
|
185
|
-
|
|
186
|
-
function UserProfile({ user, isLoggedIn }: { user: any; isLoggedIn: boolean }) {
|
|
187
|
-
return (
|
|
188
|
-
<div>
|
|
189
|
-
<h1>Profile</h1>
|
|
190
|
-
{/* Element only created if condition is true */}
|
|
191
|
-
<div k-if={isLoggedIn}>
|
|
192
|
-
<p>Welcome, {user.name}!</p>
|
|
193
|
-
<button>Logout</button>
|
|
194
|
-
</div>
|
|
195
|
-
{/* Element only created if condition is true */}
|
|
196
|
-
<div k-if={!isLoggedIn}>
|
|
197
|
-
<p>Please log in</p>
|
|
198
|
-
<button>Login</button>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
**Array Children Support** (v0.14.1+):
|
|
206
|
-
|
|
207
|
-
```tsx
|
|
208
|
-
import { jsx } from 'kt.js';
|
|
209
|
-
|
|
210
|
-
function TodoList({ todos }: { todos: string[] }) {
|
|
211
|
-
return (
|
|
212
|
-
<div>
|
|
213
|
-
<h2>Todo List</h2>
|
|
214
|
-
<ul>
|
|
215
|
-
{/* Map arrays directly as children */}
|
|
216
|
-
{todos.map((todo) => (
|
|
217
|
-
<li>{todo}</li>
|
|
218
|
-
))}
|
|
219
|
-
</ul>
|
|
220
|
-
</div>
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Mix mapped elements with other elements
|
|
225
|
-
function MixedList({ items }: { items: string[] }) {
|
|
226
|
-
return (
|
|
227
|
-
<ul>
|
|
228
|
-
<li>Header Item</li>
|
|
229
|
-
{items.map((item) => (
|
|
230
|
-
<li>{item}</li>
|
|
231
|
-
))}
|
|
232
|
-
<li>Footer Item</li>
|
|
233
|
-
</ul>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Async Components with KTAsync
|
|
239
|
-
|
|
240
|
-
KT.js provides built-in support for async components through the `KTAsync` component:
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
import { KTAsync, ref } from 'kt.js';
|
|
244
|
-
|
|
245
|
-
// Define an async component that returns a Promise<HTMLElement>
|
|
246
|
-
const AsyncUserCard = function () {
|
|
247
|
-
return fetch('/api/user')
|
|
248
|
-
.then((res) => res.json())
|
|
249
|
-
.then((user) => (
|
|
250
|
-
<div class="user-card">
|
|
251
|
-
<h2>{user.name}</h2>
|
|
252
|
-
<p>{user.email}</p>
|
|
253
|
-
</div>
|
|
254
|
-
));
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
// Use KTAsync to handle the async component
|
|
258
|
-
function App() {
|
|
259
|
-
return (
|
|
260
|
-
<div class="app">
|
|
261
|
-
<h1>User Profile</h1>
|
|
262
|
-
<KTAsync component={AsyncUserCard} />
|
|
263
|
-
</div>
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// The component starts with a placeholder comment node
|
|
268
|
-
// When the Promise resolves, it automatically replaces with the actual element
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
**How KTAsync works:**
|
|
272
|
-
|
|
273
|
-
1. Creates a placeholder comment node (`ktjs-suspense-placeholder`) immediately
|
|
274
|
-
2. Calls your component function (which should return a `Promise<HTMLElement>` or `HTMLElement`)
|
|
275
|
-
3. When the Promise resolves, automatically replaces the placeholder with the resolved element
|
|
276
|
-
4. If your component returns a non-Promise value, it's used directly without async handling
|
|
277
|
-
|
|
278
|
-
**Example with dynamic updates:**
|
|
279
|
-
|
|
280
|
-
```tsx
|
|
281
|
-
const DynamicContent = function () {
|
|
282
|
-
const count = ref(0);
|
|
283
|
-
const container = (
|
|
284
|
-
<div>
|
|
285
|
-
<p>Count: {count}</p>
|
|
286
|
-
<button on:click={() => count.value++}>Increment</button>
|
|
287
|
-
</div>
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
// Simulate async data loading
|
|
291
|
-
return new Promise<HTMLElement>((resolve) => {
|
|
292
|
-
setTimeout(() => resolve(container), 500);
|
|
293
|
-
});
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
// Usage
|
|
297
|
-
const app = (
|
|
298
|
-
<div>
|
|
299
|
-
<h1>Loading async content...</h1>
|
|
300
|
-
<KTAsync component={DynamicContent} />
|
|
301
|
-
</div>
|
|
302
|
-
);
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
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:
|
|
306
|
-
|
|
307
|
-
```ts
|
|
308
|
-
const button = btn(
|
|
309
|
-
{
|
|
310
|
-
dblclick: '22',
|
|
311
|
-
'on:dblclick': function trueHandler() {
|
|
312
|
-
/* ... */
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
'Click me',
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
// This is equivalent to:
|
|
319
|
-
const button = btn(undefined, 'Click me');
|
|
320
|
-
button.setAttribute('dblclick', '22');
|
|
321
|
-
button.addEventListener('click', () => alert('Clicked!'));
|
|
322
|
-
button.addEventListener('dblclick', function trueHandler() {
|
|
323
|
-
/* ... */
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Working with CSS-in-JS Libraries
|
|
328
|
-
|
|
329
|
-
KT.js works seamlessly with CSS-in-JS libraries like `@emotion/css`:
|
|
330
|
-
|
|
331
|
-
```ts
|
|
332
|
-
import { css } from '@emotion/css';
|
|
333
|
-
import { h, div } from 'kt.js';
|
|
334
|
-
|
|
335
|
-
const className = css`
|
|
336
|
-
color: red;
|
|
337
|
-
font-size: 20px;
|
|
338
|
-
`;
|
|
339
|
-
|
|
340
|
-
// Pass class name as attribute
|
|
341
|
-
h('div', { class: className }, 'Styled text');
|
|
342
|
-
|
|
343
|
-
// Or as the first string argument
|
|
344
|
-
div(className, 'Styled text');
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Using Shortcuts with Default Values
|
|
348
|
-
|
|
349
|
-
The `withDefaults` function allows you to create element factories with predefined properties:
|
|
350
|
-
|
|
351
|
-
```ts
|
|
352
|
-
import { withDefaults, div, button } from 'kt.js';
|
|
353
|
-
|
|
354
|
-
// Create a styled div factory
|
|
355
|
-
const card = withDefaults(div, { class: 'card' });
|
|
356
|
-
const blueCard = withDefaults(card, { style: 'background: blue' });
|
|
357
|
-
|
|
358
|
-
// Use them
|
|
359
|
-
const myCard = card('card-body', 'Content'); // <div class="card"><div class="card-body">Content</div></div>
|
|
360
|
-
const myBlueCard = blueCard('title', 'Blue!'); // <div class="card" style="background: blue"><div class="title">Blue!</div></div>
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
## Router
|
|
364
|
-
|
|
365
|
-
The router is available as a separate package `@ktjs/router`:
|
|
366
|
-
|
|
367
|
-
```ts
|
|
368
|
-
import { createRouter } from '@ktjs/router';
|
|
369
|
-
import { div, h1 } from 'kt.js';
|
|
370
|
-
|
|
371
|
-
const router = createRouter({
|
|
372
|
-
routes: [
|
|
373
|
-
{
|
|
374
|
-
path: '/',
|
|
375
|
-
name: 'home',
|
|
376
|
-
beforeEnter: (to) => {
|
|
377
|
-
// Render your page here
|
|
378
|
-
document.getElementById('app')!.innerHTML = '';
|
|
379
|
-
document.getElementById('app')!.appendChild(div({}, [h1({}, 'Home Page')]));
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
path: '/user/:id',
|
|
384
|
-
name: 'user',
|
|
385
|
-
beforeEnter: (to) => {
|
|
386
|
-
// Route-specific guard and rendering
|
|
387
|
-
console.log('Entering user page');
|
|
388
|
-
document.getElementById('app')!.innerHTML = '';
|
|
389
|
-
document.getElementById('app')!.appendChild(div({}, [h1({}, `User ${to.params.id}`)]));
|
|
390
|
-
return true;
|
|
391
|
-
},
|
|
392
|
-
},
|
|
393
|
-
],
|
|
394
|
-
beforeEach: async (to, from) => {
|
|
395
|
-
// Global navigation guard - return false to block navigation
|
|
396
|
-
console.log('Navigating to:', to.path);
|
|
397
|
-
return true;
|
|
398
|
-
},
|
|
399
|
-
afterEach: (to) => {
|
|
400
|
-
// Called after successful navigation
|
|
401
|
-
document.title = to.name || to.path;
|
|
402
|
-
},
|
|
403
|
-
onError: (error) => {
|
|
404
|
-
console.error('Router error:', error);
|
|
405
|
-
},
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// Navigate programmatically
|
|
409
|
-
router.push('/user/123');
|
|
410
|
-
router.push('/user/456?page=2');
|
|
411
|
-
|
|
412
|
-
// Navigate by route name
|
|
413
|
-
router.push({ name: 'user', params: { id: '789' } });
|
|
414
|
-
|
|
415
|
-
// Get current route
|
|
416
|
-
console.log(router.current?.path, router.current?.params, router.current?.query);
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Router Features
|
|
420
|
-
|
|
421
|
-
- **Hash-based Routing Only** (v0.14.7+): Uses URL hash for client-side navigation (`#/path`)
|
|
422
|
-
- **Dynamic Parameters**: Support for dynamic route segments (`/user/:id`)
|
|
423
|
-
- **Query Strings**: Automatic parsing of query parameters (`?key=value`)
|
|
424
|
-
- **Named Routes**: Navigate using route names instead of paths
|
|
425
|
-
- **Async Navigation Guards**:
|
|
426
|
-
- `beforeEach`: Global guard before navigation (async)
|
|
427
|
-
- `beforeEnter`: Per-route guard (can also be used for rendering, async)
|
|
428
|
-
- `afterEach`: Global hook after navigation
|
|
429
|
-
- All guards support Promise-based async operations
|
|
430
|
-
- Guards can return `false` to cancel, string/object to redirect
|
|
431
|
-
- `GuardLevel` for fine-grained control over guard execution
|
|
432
|
-
- **Error Handling**: `onError` and `onNotFound` callbacks
|
|
433
|
-
- **Optimized Performance**: Pre-flattened routes and efficient matching algorithm
|
|
434
|
-
- **Zero Dependencies**: Fully self-contained router implementation (does not require `@ktjs/core` for runtime, only for TypeScript types)
|
|
435
|
-
- **Pure Routing**: No rendering logic - you control the DOM
|
|
436
|
-
- **Automatic Initialization**: Router auto-initializes on creation (v0.14.7+)
|
|
437
|
-
|
|
438
|
-
## Browser Compatibility
|
|
439
|
-
|
|
440
|
-
KT.js is transpiled to ES5 and works in all modern browsers as well as legacy browsers including IE9+.
|
|
441
|
-
|
|
442
|
-
### Promise Polyfill
|
|
443
|
-
|
|
444
|
-
For environments without native `Promise` support (like IE).
|
|
445
|
-
|
|
446
|
-
```js
|
|
447
|
-
import 'some promise polyfill'; // Will fallback to sync version if Promise is not available
|
|
448
|
-
import { h, div, createRouter } from 'kt.js';
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
## License
|
|
452
|
-
|
|
453
|
-
MIT
|
|
1
|
+
[See Readme](../../README.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -22,12 +22,35 @@ declare class KTRef<T> {
|
|
|
22
22
|
addOnChange(callback: RefChangeHandler<T>): void;
|
|
23
23
|
removeOnChange(callback: RefChangeHandler<T>): boolean;
|
|
24
24
|
}
|
|
25
|
+
declare const isKTRef: <T = any>(obj: any) => obj is KTRef<T>;
|
|
25
26
|
/**
|
|
26
27
|
* Reference to the created HTML element.
|
|
28
|
+
* - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
|
|
27
29
|
* - can alse be used to store normal values, but it is not reactive.
|
|
28
30
|
* @param value mostly an HTMLElement
|
|
29
31
|
*/
|
|
30
32
|
declare function ref<T = JSX.Element>(value?: T, onChange?: RefChangeHandler<T>): KTRef<T>;
|
|
33
|
+
type KTSurfaceRef<T extends Object> = {
|
|
34
|
+
[K in keyof T]: KTRef<T[K]>;
|
|
35
|
+
} & {
|
|
36
|
+
/**
|
|
37
|
+
* Get the dereferenced object like the original one
|
|
38
|
+
*/
|
|
39
|
+
kcollect: () => T;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Make all first-level properties of the object a `KTRef`.
|
|
43
|
+
* - `obj.a.b` is not reactive
|
|
44
|
+
*/
|
|
45
|
+
declare const surfaceRef: <T extends Object>(obj: T) => KTSurfaceRef<T>;
|
|
46
|
+
|
|
47
|
+
type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag
|
|
48
|
+
? SVGElementTagNameMap[T]
|
|
49
|
+
: T extends HTMLTag
|
|
50
|
+
? HTMLElementTagNameMap[T]
|
|
51
|
+
: T extends MathMLTag
|
|
52
|
+
? MathMLElementTagNameMap[T]
|
|
53
|
+
: HTMLElement;
|
|
31
54
|
|
|
32
55
|
type SingleContent = KTRef<any> | HTMLElement | Element | Node | string | number | boolean | null | undefined;
|
|
33
56
|
type KTAvailableContent = SingleContent | KTAvailableContent[];
|
|
@@ -48,7 +71,14 @@ interface KTBaseAttribute {
|
|
|
48
71
|
|
|
49
72
|
// # kt-specific attributes
|
|
50
73
|
ref?: KTRef<JSX.Element>;
|
|
74
|
+
|
|
75
|
+
// todo 是否要让k-if是KTRef的时候具备响应能力?
|
|
76
|
+
/**
|
|
77
|
+
* If a `KTRef` is bound, it will be reactive; otherwise, it will be static.
|
|
78
|
+
*/
|
|
51
79
|
'k-if'?: any;
|
|
80
|
+
// todo k-model如何指定value还是checked还是别的什么?
|
|
81
|
+
'k-model'?: KTRef<any>;
|
|
52
82
|
|
|
53
83
|
// # normal HTML attributes
|
|
54
84
|
id?: string;
|
|
@@ -117,7 +147,6 @@ type KTComponent = (
|
|
|
117
147
|
any,
|
|
118
148
|
) => JSX.Element | Promise<JSX.Element> | any;
|
|
119
149
|
|
|
120
|
-
type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SVGTag ? SVGElementTagNameMap[T] : T extends HTMLTag ? HTMLElementTagNameMap[T] : T extends MathMLTag ? MathMLElementTagNameMap[T] : HTMLElement;
|
|
121
150
|
/**
|
|
122
151
|
* Create an enhanced HTMLElement.
|
|
123
152
|
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
@@ -128,7 +157,7 @@ type HTML<T extends (HTMLTag | SVGTag | MathMLTag) & otherstring> = T extends SV
|
|
|
128
157
|
* ## About
|
|
129
158
|
* @package @ktjs/core
|
|
130
159
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
131
|
-
* @version 0.
|
|
160
|
+
* @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
|
|
132
161
|
* @license MIT
|
|
133
162
|
* @link https://github.com/baendlorel/kt.js
|
|
134
163
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -1433,5 +1462,5 @@ interface KTForProps<T> {
|
|
|
1433
1462
|
*/
|
|
1434
1463
|
declare function KTFor<T>(props: KTForProps<T>): KTForElement;
|
|
1435
1464
|
|
|
1436
|
-
export { Fragment, KTAsync, KTFor, KTRef, h as createElement, createRedrawable, h, jsx, jsxDEV, jsxs, ref };
|
|
1437
|
-
export type { EventHandler, HTMLTag, KTAttribute, KTForElement, KTForProps, KTRawAttr, KTRawContent, KTRawContents };
|
|
1465
|
+
export { Fragment, KTAsync, KTFor, KTRef, h as createElement, createRedrawable, h, isKTRef, jsx, jsxDEV, jsxs, ref, surfaceRef };
|
|
1466
|
+
export type { EventHandler, HTMLTag, KTAttribute, KTForElement, KTForProps, KTRawAttr, KTRawContent, KTRawContents, KTSurfaceRef };
|
package/dist/index.iife.js
CHANGED
|
@@ -3,6 +3,7 @@ var __ktjs_core__ = (function (exports) {
|
|
|
3
3
|
|
|
4
4
|
// Cached native methods for performance optimization
|
|
5
5
|
const $isArray = Array.isArray;
|
|
6
|
+
const $entries = Object.entries;
|
|
6
7
|
const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
7
8
|
|
|
8
9
|
// Error handling utilities
|
|
@@ -12,6 +13,7 @@ var __ktjs_core__ = (function (exports) {
|
|
|
12
13
|
|
|
13
14
|
// DOM manipulation utilities
|
|
14
15
|
// # dom natives
|
|
16
|
+
const $replaceWith = Element.prototype.replaceWith;
|
|
15
17
|
/**
|
|
16
18
|
* & Remove `bind` because it is shockingly slower than wrapper
|
|
17
19
|
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
@@ -51,7 +53,7 @@ var __ktjs_core__ = (function (exports) {
|
|
|
51
53
|
|
|
52
54
|
// Shared utilities and cached native methods for kt.js framework
|
|
53
55
|
// Re-export all utilities
|
|
54
|
-
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.
|
|
56
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
|
|
55
57
|
|
|
56
58
|
const booleanHandler = (element, key, value) => {
|
|
57
59
|
if (key in element) {
|
|
@@ -194,7 +196,6 @@ var __ktjs_core__ = (function (exports) {
|
|
|
194
196
|
}
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
document.createElement('div');
|
|
198
199
|
const htmlCreator = (tag) => document.createElement(tag);
|
|
199
200
|
const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
200
201
|
const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
|
|
@@ -212,7 +213,7 @@ var __ktjs_core__ = (function (exports) {
|
|
|
212
213
|
* ## About
|
|
213
214
|
* @package @ktjs/core
|
|
214
215
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
215
|
-
* @version 0.
|
|
216
|
+
* @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
|
|
216
217
|
* @license MIT
|
|
217
218
|
* @link https://github.com/baendlorel/kt.js
|
|
218
219
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
@@ -241,14 +242,6 @@ var __ktjs_core__ = (function (exports) {
|
|
|
241
242
|
// * Handle content
|
|
242
243
|
applyAttr(element, attr);
|
|
243
244
|
applyContent(element, content);
|
|
244
|
-
// if (tag === 'svg') {
|
|
245
|
-
// tempWrapper.innerHTML = element.outerHTML;
|
|
246
|
-
// return tempWrapper.firstChild as HTML<T>;
|
|
247
|
-
// }
|
|
248
|
-
// if (tag === 'math') {
|
|
249
|
-
// tempWrapper.innerHTML = element.outerHTML;
|
|
250
|
-
// return tempWrapper.firstChild as HTML<T>;
|
|
251
|
-
// }
|
|
252
245
|
return element;
|
|
253
246
|
};
|
|
254
247
|
|
|
@@ -305,37 +298,85 @@ var __ktjs_core__ = (function (exports) {
|
|
|
305
298
|
return false;
|
|
306
299
|
}
|
|
307
300
|
}
|
|
301
|
+
const isKTRef = (obj) => {
|
|
302
|
+
return typeof obj === 'object' && obj !== null && obj.isKT === true;
|
|
303
|
+
};
|
|
308
304
|
/**
|
|
309
305
|
* Reference to the created HTML element.
|
|
306
|
+
* - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
|
|
310
307
|
* - can alse be used to store normal values, but it is not reactive.
|
|
311
308
|
* @param value mostly an HTMLElement
|
|
312
309
|
*/
|
|
313
310
|
function ref(value, onChange) {
|
|
314
311
|
return new KTRef(value, onChange ? [onChange] : []);
|
|
315
312
|
}
|
|
313
|
+
function kcollect() {
|
|
314
|
+
const newObj = {};
|
|
315
|
+
const entries = $entries(this);
|
|
316
|
+
for (let i = 0; i < entries.length; i++) {
|
|
317
|
+
const key = entries[i][0];
|
|
318
|
+
if (key === 'kcollect') {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
newObj[key] = entries[i][1].value;
|
|
322
|
+
}
|
|
323
|
+
return newObj;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Make all first-level properties of the object a `KTRef`.
|
|
327
|
+
* - `obj.a.b` is not reactive
|
|
328
|
+
*/
|
|
329
|
+
const surfaceRef = (obj) => {
|
|
330
|
+
const entries = $entries(obj);
|
|
331
|
+
const newObj = { kcollect };
|
|
332
|
+
for (let i = 0; i < entries.length; i++) {
|
|
333
|
+
newObj[entries[i][0]] = ref(entries[i][1]);
|
|
334
|
+
}
|
|
335
|
+
return newObj;
|
|
336
|
+
};
|
|
316
337
|
|
|
317
338
|
const dummyRef = { value: null };
|
|
339
|
+
const create = (tag, props) => {
|
|
340
|
+
if (typeof tag === 'function') {
|
|
341
|
+
return tag(props);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
return h(tag, props, props.children);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
const placeholder = () => document.createComment('k-if');
|
|
318
348
|
/**
|
|
319
349
|
* @param tag html tag or function component
|
|
320
350
|
* @param props properties/attributes
|
|
321
351
|
*/
|
|
322
352
|
function jsx(tag, props) {
|
|
323
|
-
const
|
|
353
|
+
const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
|
|
324
354
|
let el;
|
|
325
|
-
if ('k-if' in props
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
355
|
+
if ('k-if' in props) {
|
|
356
|
+
const kif = props['k-if'];
|
|
357
|
+
let condition = kif; // assume boolean by default
|
|
358
|
+
// Handle reactive k-if
|
|
359
|
+
if (isKTRef(kif)) {
|
|
360
|
+
kif.addOnChange((newValue, oldValue) => {
|
|
361
|
+
if (newValue === oldValue) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const oldEl = el;
|
|
365
|
+
el = newValue ? create(tag, props) : placeholder();
|
|
366
|
+
$replaceWith.call(oldEl, el);
|
|
367
|
+
maybeDummyRef.value = el;
|
|
368
|
+
});
|
|
369
|
+
condition = kif.value;
|
|
370
|
+
}
|
|
371
|
+
if (!condition) {
|
|
372
|
+
// & make comment placeholder in case that ref might be redrawn later
|
|
373
|
+
el = placeholder();
|
|
374
|
+
maybeDummyRef.value = el;
|
|
375
|
+
return el;
|
|
376
|
+
}
|
|
337
377
|
}
|
|
338
|
-
|
|
378
|
+
el = create(tag, props);
|
|
379
|
+
maybeDummyRef.value = el;
|
|
339
380
|
return el;
|
|
340
381
|
}
|
|
341
382
|
/**
|
|
@@ -634,10 +675,12 @@ var __ktjs_core__ = (function (exports) {
|
|
|
634
675
|
exports.createElement = h;
|
|
635
676
|
exports.createRedrawable = createRedrawable;
|
|
636
677
|
exports.h = h;
|
|
678
|
+
exports.isKTRef = isKTRef;
|
|
637
679
|
exports.jsx = jsx;
|
|
638
680
|
exports.jsxDEV = jsxDEV;
|
|
639
681
|
exports.jsxs = jsxs;
|
|
640
682
|
exports.ref = ref;
|
|
683
|
+
exports.surfaceRef = surfaceRef;
|
|
641
684
|
|
|
642
685
|
return exports;
|
|
643
686
|
|