kt.js 0.20.2 → 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 CHANGED
@@ -2,11 +2,7 @@
2
2
 
3
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
- [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.
5
+ [CHANGLOG✨](../CHANGELOG.md)
10
6
 
11
7
  > 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
8
 
@@ -21,6 +17,7 @@ KT.js is now a **monorepo** containing multiple packages:
21
17
  - **[kt.js](./packages/kt.js)**: Main entry package that re-exports all functionality
22
18
  - **[@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
19
  - **[@ktjs/router](./packages/router)**: Client-side routing with navigation guards (not included in kt.js package)
20
+ - **[@ktjs/mui](./packages/mui)**: Material UI components built on top of KT.js (not included in kt.js package)
24
21
 
25
22
  You can install the full package or individual packages as needed:
26
23
 
@@ -28,10 +25,8 @@ You can install the full package or individual packages as needed:
28
25
  pnpm add kt.js
29
26
 
30
27
  # Or install individual packages
31
- pnpm add @ktjs/core # Core DOM utilities (independent)
32
28
  pnpm add @ktjs/router # Client-side router (requires @ktjs/core)
33
29
  pnpm add @ktjs/mui # Material UI components (requires @ktjs/core)
34
- pnpm add @ktjs/shortcuts # Shortcuts (requires @ktjs/core)
35
30
  ```
36
31
 
37
32
  ## Philosophy
@@ -40,414 +35,140 @@ As a web framework, repeatedly creating a large number of variables and objects
40
35
 
41
36
  KT.js follows one rule: **full control of DOM and avoid unnecessary repainting**.
42
37
 
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+):
38
+ ## Core Features (@ktjs/core)
206
39
 
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
- }
40
+ ### JSX/TSX Support
223
41
 
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:
42
+ KT.js provides first-class JSX/TSX support with zero virtual DOM overhead. JSX compiles directly to `h()` function calls.
241
43
 
242
44
  ```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:**
45
+ import { h } from '@ktjs/core';
272
46
 
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:**
47
+ // Function components
48
+ const Button = ({ onClick, children }) => (
49
+ <button on:click={onClick} class="btn">
50
+ {children}
51
+ </button>
52
+ );
279
53
 
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>
54
+ // Conditional rendering with k-if
55
+ const UserCard = ({ user, showDetails }) => (
56
+ <div class="card">
57
+ <h3>{user.name}</h3>
58
+ <div k-if={showDetails}>
59
+ <p>Email: {user.email}</p>
60
+ <p>Role: {user.role}</p>
287
61
  </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
62
  </div>
302
63
  );
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
64
 
307
- ```ts
308
- const button = btn(
309
- {
310
- dblclick: '22',
311
- 'on:dblclick': function trueHandler() {
312
- /* ... */
313
- },
314
- },
315
- 'Click me',
316
- );
65
+ // List rendering with KTFor
66
+ const UserList = ({ users }) => <KTFor list={users} key={(user) => user.id} map={(user) => <UserCard user={user} />} />;
317
67
 
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
- });
68
+ // Async components
69
+ const AsyncContent = async () => {
70
+ const data = await fetchData();
71
+ return <div>{data}</div>;
72
+ };
325
73
  ```
326
74
 
327
- ### Working with CSS-in-JS Libraries
328
-
329
- KT.js works seamlessly with CSS-in-JS libraries like `@emotion/css`:
75
+ ### Reactive References
330
76
 
331
- ```ts
332
- import { css } from '@emotion/css';
333
- import { h, div } from 'kt.js';
77
+ Create reactive values with `ref()` and listen to changes.
334
78
 
335
- const className = css`
336
- color: red;
337
- font-size: 20px;
338
- `;
79
+ ```typescript
80
+ import { ref } from '@ktjs/core';
339
81
 
340
- // Pass class name as attribute
341
- h('div', { class: className }, 'Styled text');
82
+ const count = ref(0);
83
+ count.addOnChange((newVal, oldVal) => {
84
+ console.log(`Count changed from ${oldVal} to ${newVal}`);
85
+ });
342
86
 
343
- // Or as the first string argument
344
- div(className, 'Styled text');
87
+ // Update triggers change listeners
88
+ count.value = 1;
345
89
  ```
346
90
 
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';
91
+ ### Redraw Mechanism
353
92
 
354
- // Create a styled div factory
355
- const card = withDefaults(div, { class: 'card' });
356
- const blueCard = withDefaults(card, { style: 'background: blue' });
93
+ Update elements in-place with `redraw()` for minimal DOM updates.
357
94
 
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>
95
+ ```typescript
96
+ const element = <div class="counter">{count}</div>;
97
+ element.redraw({ class: 'counter updated' }, [count.value + 1]);
361
98
  ```
362
99
 
363
- ## Router
100
+ ## Router (@ktjs/router)
364
101
 
365
- The router is available as a separate package `@ktjs/router`:
102
+ Client-side hash-based routing with async navigation guards.
366
103
 
367
- ```ts
104
+ ### Basic Routing
105
+
106
+ ```typescript
368
107
  import { createRouter } from '@ktjs/router';
369
- import { div, h1 } from 'kt.js';
370
108
 
371
109
  const router = createRouter({
372
110
  routes: [
373
111
  {
374
112
  path: '/',
375
113
  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
- },
114
+ component: () => <HomePage />
381
115
  },
382
116
  {
383
117
  path: '/user/:id',
384
118
  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
- },
119
+ component: (to) => <UserPage id={to.params.id} />
120
+ }
393
121
  ],
394
122
  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
- },
123
+ // Auth check
124
+ if (to.path === '/admin' && !isAdmin()) {
125
+ return '/login';
126
+ }
127
+ }
406
128
  });
129
+ ```
407
130
 
408
- // Navigate programmatically
409
- router.push('/user/123');
410
- router.push('/user/456?page=2');
131
+ ### Navigation
411
132
 
412
- // Navigate by route name
413
- router.push({ name: 'user', params: { id: '789' } });
133
+ ```typescript
134
+ // Programmatic navigation
135
+ router.push('/user/123');
136
+ router.push({ name: 'user', params: { id: '456' } });
414
137
 
415
- // Get current route
416
- console.log(router.current?.path, router.current?.params, router.current?.query);
138
+ // Access current route
139
+ console.log(router.current?.path, router.current?.params);
417
140
  ```
418
141
 
419
- ### Router Features
142
+ ## Installation
420
143
 
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
144
+ ```bash
145
+ # Full package (includes core)
146
+ pnpm add kt.js
439
147
 
440
- KT.js is transpiled to ES5 and works in all modern browsers as well as legacy browsers including IE9+.
148
+ # Individual packages
149
+ pnpm add @ktjs/core @ktjs/router
150
+ ```
441
151
 
442
- ### Promise Polyfill
152
+ ## TypeScript Configuration
443
153
 
444
- For environments without native `Promise` support (like IE).
154
+ For JSX/TSX support, configure your `tsconfig.json`:
445
155
 
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';
156
+ ```json
157
+ {
158
+ "compilerOptions": {
159
+ "jsx": "react-jsx",
160
+ "jsxImportSource": "@ktjs/core"
161
+ }
162
+ }
449
163
  ```
450
164
 
165
+ ## Philosophy
166
+
167
+ - **Direct DOM Manipulation**: No virtual DOM, minimal abstraction
168
+ - **Zero Re-renders**: Update only what changes, avoid full component re-renders
169
+ - **Type Safety**: Full TypeScript support with accurate type inference
170
+ - **Lightweight**: Small bundle size, no unnecessary dependencies
171
+
451
172
  ## License
452
173
 
453
174
  MIT
@@ -9,6 +9,7 @@ const $throw = (message) => {
9
9
 
10
10
  // DOM manipulation utilities
11
11
  // # dom natives
12
+ const $replaceWith = Element.prototype.replaceWith;
12
13
  /**
13
14
  * & Remove `bind` because it is shockingly slower than wrapper
14
15
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -48,7 +49,7 @@ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwn
48
49
 
49
50
  // Shared utilities and cached native methods for kt.js framework
50
51
  // Re-export all utilities
51
- Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
52
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.2' });
52
53
 
53
54
  const booleanHandler = (element, key, value) => {
54
55
  if (key in element) {
@@ -191,7 +192,6 @@ function applyContent(element, content) {
191
192
  }
192
193
  }
193
194
 
194
- document.createElement('div');
195
195
  const htmlCreator = (tag) => document.createElement(tag);
196
196
  const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
197
197
  const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
@@ -209,7 +209,7 @@ const MATHML_ATTR_FLAG = '__kt_mathml__';
209
209
  * ## About
210
210
  * @package @ktjs/core
211
211
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
212
- * @version 0.20.2 (Last Update: 2026.02.01 18:34:51.151)
212
+ * @version 0.21.1 (Last Update: 2026.02.02 09:20:07.959)
213
213
  * @license MIT
214
214
  * @link https://github.com/baendlorel/kt.js
215
215
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -238,14 +238,6 @@ const h = (tag, attr, content) => {
238
238
  // * Handle content
239
239
  applyAttr(element, attr);
240
240
  applyContent(element, content);
241
- // if (tag === 'svg') {
242
- // tempWrapper.innerHTML = element.outerHTML;
243
- // return tempWrapper.firstChild as HTML<T>;
244
- // }
245
- // if (tag === 'math') {
246
- // tempWrapper.innerHTML = element.outerHTML;
247
- // return tempWrapper.firstChild as HTML<T>;
248
- // }
249
241
  return element;
250
242
  };
251
243
 
@@ -254,7 +246,13 @@ class KTRef {
254
246
  * Indicates that this is a KTRef instance
255
247
  */
256
248
  isKT = true;
249
+ /**
250
+ * @internal
251
+ */
257
252
  _value;
253
+ /**
254
+ * @internal
255
+ */
258
256
  _onChanges;
259
257
  constructor(_value, _onChanges) {
260
258
  this._value = _value;
@@ -296,8 +294,12 @@ class KTRef {
296
294
  return false;
297
295
  }
298
296
  }
297
+ const isKTRef = (obj) => {
298
+ return typeof obj === 'object' && obj !== null && obj.isKT === true;
299
+ };
299
300
  /**
300
301
  * Reference to the created HTML element.
302
+ * - **Only** respond to `ref.value` changes, not reactive to internal changes of the element.
301
303
  * - can alse be used to store normal values, but it is not reactive.
302
304
  * @param value mostly an HTMLElement
303
305
  */
@@ -306,27 +308,47 @@ function ref(value, onChange) {
306
308
  }
307
309
 
308
310
  const dummyRef = { value: null };
311
+ const create = (tag, props) => {
312
+ if (typeof tag === 'function') {
313
+ return tag(props);
314
+ }
315
+ else {
316
+ return h(tag, props, props.children);
317
+ }
318
+ };
319
+ const placeholder = () => document.createComment('k-if');
309
320
  /**
310
321
  * @param tag html tag or function component
311
322
  * @param props properties/attributes
312
323
  */
313
324
  function jsx(tag, props) {
314
- const ref = props.ref?.isKT ? props.ref : dummyRef;
325
+ const maybeDummyRef = isKTRef(props.ref) ? props.ref : dummyRef;
315
326
  let el;
316
- if ('k-if' in props && !props['k-if']) {
317
- // & make comment placeholder in case that ref might be redrawn later
318
- el = document.createComment('k-if');
319
- ref.value = el;
320
- return el;
321
- }
322
- // Handle function components
323
- if (typeof tag === 'function') {
324
- el = tag(props);
325
- }
326
- else {
327
- el = h(tag, props, props.children);
327
+ if ('k-if' in props) {
328
+ const kif = props['k-if'];
329
+ let condition = kif; // assume boolean by default
330
+ // Handle reactive k-if
331
+ if (isKTRef(kif)) {
332
+ kif.addOnChange((newValue, oldValue) => {
333
+ if (newValue === oldValue) {
334
+ return;
335
+ }
336
+ const oldEl = el;
337
+ el = newValue ? create(tag, props) : placeholder();
338
+ $replaceWith.call(oldEl, el);
339
+ maybeDummyRef.value = el;
340
+ });
341
+ condition = kif.value;
342
+ }
343
+ if (!condition) {
344
+ // & make comment placeholder in case that ref might be redrawn later
345
+ el = placeholder();
346
+ maybeDummyRef.value = el;
347
+ return el;
348
+ }
328
349
  }
329
- ref.value = el;
350
+ el = create(tag, props);
351
+ maybeDummyRef.value = el;
330
352
  return el;
331
353
  }
332
354
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kt.js",
3
- "version": "0.20.2",
3
+ "version": "0.21.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.20.2"
44
+ "@ktjs/core": "0.21.1"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "rollup -c rollup.config.mjs",