lithent 1.21.2 → 1.21.4

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,126 @@
1
+ # Lithent Agent Addon
2
+
3
+ > Version: 1.21.4
4
+
5
+ You are a coding agent with Lithent virtual DOM guidance enabled.
6
+
7
+ ACTIVATION CONDITIONS:
8
+
9
+ These guidelines apply ONLY when Lithent is installed in the current project.
10
+
11
+ Before suggesting Lithent patterns, verify Lithent availability:
12
+ 1. Check if `package.json` contains lithent in dependencies or devDependencies
13
+ 2. Check if `node_modules/lithent` directory exists
14
+ 3. Check if lithent imports are present in existing code
15
+
16
+ If Lithent is NOT installed:
17
+ - Do not enforce these guidelines
18
+ - Use standard coding practices appropriate for the project
19
+ - Never suggest installing lithent unless explicitly requested
20
+
21
+ If Lithent IS installed:
22
+ - Apply all guidelines below
23
+ - Suggest Lithent patterns for UI component creation
24
+ - Prioritize closure-based state management patterns
25
+
26
+ CODING GUIDELINES:
27
+
28
+ 1. COMPONENT MODE SELECTION
29
+ - Use `mount` for explicit render control with `renew()`
30
+ - Use `lmount` for automatic reactivity with `lstate`/`lstore`
31
+ - Don't mix modes: use `state`/`store` with `mount`, use `lstate`/`lstore` with `lmount`
32
+ - Suggest `lmount` for simpler components, `mount` for fine-grained control
33
+
34
+ 2. COMPONENT STRUCTURE
35
+ - Outer function (mounter) runs once for initialization
36
+ - Inner function (updater) runs on every render
37
+ - Keep state setup in mounter, return JSX from updater
38
+ - Always return a function from mounter, never JSX directly
39
+
40
+ 3. STATE MANAGEMENT
41
+ - Use `state(initialValue, renew)` with `mount` components
42
+ - Use `lstate(initialValue)` with `lmount` components
43
+ - Access values via `.value` property
44
+ - For global state, use `store`/`lstore` instead of prop drilling
45
+ - Use `computed` for derived values, `effect` for side effects
46
+
47
+ 4. LIFECYCLE HOOKS
48
+ - Use `mountCallback` for setup after mount (return cleanup function)
49
+ - Use `updateCallback` for logic before each update
50
+ - Use `mountReadyCallback` for logic after initial render
51
+ - Place hooks in mounter function, not in updater
52
+
53
+ 5. LIST RENDERING
54
+ - Always use `key` prop for list items
55
+ - Keys must be unique and stable (prefer IDs over indices)
56
+ - Suggest adding keys when iterating over arrays without them
57
+
58
+ 6. PERFORMANCE OPTIMIZATION
59
+ - Suggest `cacheUpdate` when multiple state updates cause re-renders
60
+ - Suggest `nextTickRender` for deferring expensive renders
61
+ - Avoid creating new functions in updater when possible
62
+ - Move event handlers to mounter scope when they don't need updater closure
63
+
64
+ 7. SSR AND HYDRATION
65
+ - Use `renderToString` for server-side rendering
66
+ - Use `hydration` flag with `render` for client-side hydration
67
+ - Ensure component output is deterministic for hydration to work
68
+
69
+ 8. TEMPLATE ALTERNATIVES
70
+ - Prefer JSX for most cases
71
+ - Suggest `fTags` for no-build-step environments
72
+ - Suggest `lTag` (HTM) for template literal preference
73
+ - Don't mix template styles within a single component
74
+
75
+ 9. CONTEXT USAGE
76
+ - Use `createContext` with `mount`, `createLContext` with `lmount`
77
+ - Pass `renew` to `useContext()` in manual mode
78
+ - Suggest context over deep prop drilling (3+ levels)
79
+
80
+ 10. CHILDREN HANDLING
81
+ - Use `unwrapChildren` helper when manipulating children
82
+ - Access children as third parameter in mounter function
83
+ - Don't modify children directly, wrap or filter them
84
+
85
+ IMPORT PATHS:
86
+ - Core: `import { mount, lmount, render, h, Fragment, portal, ref, nextTick } from 'lithent'`
87
+ - Lifecycle: `import { mountCallback, updateCallback, mountReadyCallback } from 'lithent'`
88
+ - Helper (manual): `import { state, store, createContext, computed, effect } from 'lithent/helper'`
89
+ - Helper (light): `import { lstate, lstore, createLContext } from 'lithent/helper'`
90
+ - Helper (utils): `import { cacheUpdate, nextTickRender, unwrapChildren } from 'lithent/helper'`
91
+ - SSR: `import { renderToString, hydration } from 'lithent/ssr'`
92
+ - FTags: `import { fTags, fFragment, fMount } from 'lithent/ftags'`
93
+ - HTM: `import { lTag } from 'lithent/tag'`
94
+
95
+ GUIDANCE APPROACH:
96
+
97
+ When user creates UI components:
98
+ 1. Suggest appropriate component mode (mount vs lmount)
99
+ 2. Ensure proper mounter/updater structure
100
+ 3. Add keys to list renderings if missing
101
+
102
+ When reviewing existing Lithent code:
103
+ 1. Check for mode consistency (don't mix state/lstate)
104
+ 2. Suggest lifecycle hooks for side effects
105
+ 3. Recommend performance optimizations when applicable
106
+
107
+ When user requests could benefit from Lithent patterns:
108
+ 1. Provide solution using Lithent idioms
109
+ 2. Explain the closure-based component model
110
+ 3. If user prefers different approach, respect their choice
111
+
112
+ COMMON MISTAKES TO CATCH:
113
+ - Returning JSX directly from mounter instead of returning a function
114
+ - Using `state` without passing `renew` parameter
115
+ - Using `lstate` with `mount` instead of `lmount`
116
+ - Missing `key` prop in list iterations
117
+ - Calling hooks inside updater instead of mounter
118
+ - Mutating state directly instead of using `.value`
119
+
120
+ REFERENCE MATERIALS (NOT PART OF BEHAVIORAL RULES):
121
+
122
+ For detailed code examples and API usage, refer to:
123
+ node_modules/lithent/dist/lithent-skills.md
124
+
125
+ This reference material provides comprehensive examples, patterns,
126
+ and import references that complement the behavioral guidelines above.
@@ -0,0 +1,365 @@
1
+ # Lithent Agent Skills
2
+
3
+ > Version: 1.21.4
4
+
5
+ This file provides AI agent skills for working with the Lithent library.
6
+
7
+ ## Overview
8
+
9
+ Lithent is a lightweight (~4KB) JSX-based virtual DOM library with closure-based state management. It offers two component modes:
10
+ - **Manual Mode** (`mount`): Explicit control with `renew()` function
11
+ - **Light API Mode** (`lmount`): Auto-reactive with `lstate`/`lstore`
12
+
13
+ ## Component Creation
14
+
15
+ ### Manual Mode (mount)
16
+
17
+ ```tsx
18
+ import { mount, render } from 'lithent';
19
+ import { state } from 'lithent/helper';
20
+
21
+ const Counter = mount<{ initial?: number }>((renew, props) => {
22
+ const count = state(props.initial ?? 0, renew);
23
+
24
+ return () => (
25
+ <div>
26
+ <p>Count: {count.value}</p>
27
+ <button onClick={() => count.value++}>+1</button>
28
+ </div>
29
+ );
30
+ });
31
+
32
+ render(<Counter initial={10} />, document.getElementById('app')!);
33
+ ```
34
+
35
+ ### Light API Mode (lmount)
36
+
37
+ ```tsx
38
+ import { lmount, render } from 'lithent';
39
+ import { lstate } from 'lithent/helper';
40
+
41
+ const Counter = lmount<{ initial?: number }>((props) => {
42
+ const count = lstate(props.initial ?? 0);
43
+
44
+ return () => (
45
+ <div>
46
+ <p>Count: {count.value}</p>
47
+ <button onClick={() => count.value++}>+1</button>
48
+ </div>
49
+ );
50
+ });
51
+
52
+ render(<Counter initial={10} />, document.getElementById('app')!);
53
+ ```
54
+
55
+ ## State Management
56
+
57
+ ### State (Manual Mode)
58
+
59
+ ```tsx
60
+ import { mount } from 'lithent';
61
+ import { state, computed, effect } from 'lithent/helper';
62
+
63
+ const Component = mount((renew) => {
64
+ const firstName = state('John', renew);
65
+ const lastName = state('Doe', renew);
66
+
67
+ // Derived value
68
+ const fullName = computed(() => `${firstName.value} ${lastName.value}`);
69
+
70
+ // Side effect
71
+ effect(() => {
72
+ console.log('Name changed:', fullName.value);
73
+ return () => console.log('Cleanup');
74
+ });
75
+
76
+ return () => <p>{fullName.value}</p>;
77
+ });
78
+ ```
79
+
80
+ ### State (Light API Mode)
81
+
82
+ ```tsx
83
+ import { lmount } from 'lithent';
84
+ import { lstate, computed, effect } from 'lithent/helper';
85
+
86
+ const Component = lmount(() => {
87
+ const firstName = lstate('John');
88
+ const lastName = lstate('Doe');
89
+
90
+ const fullName = computed(() => `${firstName.value} ${lastName.value}`);
91
+
92
+ effect(() => {
93
+ console.log('Name changed:', fullName.value);
94
+ });
95
+
96
+ return () => <p>{fullName.value}</p>;
97
+ });
98
+ ```
99
+
100
+ ### Global Store
101
+
102
+ ```tsx
103
+ // Manual Mode
104
+ import { store } from 'lithent/helper';
105
+ const userStore = store({ name: '', loggedIn: false });
106
+
107
+ const Component = mount((renew) => {
108
+ const user = userStore(renew);
109
+ return () => <p>{user.name}</p>;
110
+ });
111
+
112
+ // Light API Mode
113
+ import { lstore } from 'lithent/helper';
114
+ const userStore = lstore({ name: '', loggedIn: false });
115
+
116
+ const Component = lmount(() => {
117
+ const user = userStore();
118
+ return () => <p>{user.name}</p>;
119
+ });
120
+ ```
121
+
122
+ ## Lifecycle Hooks
123
+
124
+ ```tsx
125
+ import { mount, mountCallback, updateCallback, mountReadyCallback } from 'lithent';
126
+
127
+ const Component = mount((renew) => {
128
+ // After mount (return cleanup function for unmount)
129
+ mountCallback(() => {
130
+ console.log('Mounted');
131
+ return () => console.log('Unmounted');
132
+ });
133
+
134
+ // Before each update
135
+ updateCallback(() => {
136
+ console.log('Will update');
137
+ });
138
+
139
+ // After initial render complete
140
+ mountReadyCallback(() => {
141
+ console.log('Initial render done');
142
+ });
143
+
144
+ return () => <div>Hello</div>;
145
+ });
146
+ ```
147
+
148
+ ## DOM References
149
+
150
+ ```tsx
151
+ import { mount, ref } from 'lithent';
152
+
153
+ const Component = mount((renew) => {
154
+ const inputRef = ref<HTMLInputElement>(null);
155
+
156
+ const focusInput = () => inputRef.value?.focus();
157
+
158
+ return () => (
159
+ <div>
160
+ <input ref={inputRef} type="text" />
161
+ <button onClick={focusInput}>Focus</button>
162
+ </div>
163
+ );
164
+ });
165
+ ```
166
+
167
+ ## Context API
168
+
169
+ ```tsx
170
+ // Manual Mode
171
+ import { mount } from 'lithent';
172
+ import { createContext } from 'lithent/helper';
173
+
174
+ const ThemeContext = createContext<{ theme: string }>();
175
+
176
+ const Provider = mount((renew, _props, children) => {
177
+ return () => (
178
+ <ThemeContext.Provider value={{ theme: 'dark' }}>
179
+ {children}
180
+ </ThemeContext.Provider>
181
+ );
182
+ });
183
+
184
+ const Consumer = mount((renew) => {
185
+ const { theme } = ThemeContext.useContext(renew);
186
+ return () => <p>{theme}</p>;
187
+ });
188
+
189
+ // Light API Mode
190
+ import { lmount } from 'lithent';
191
+ import { createLContext } from 'lithent/helper';
192
+
193
+ const ThemeContext = createLContext<{ theme: string }>();
194
+
195
+ const Consumer = lmount(() => {
196
+ const { theme } = ThemeContext.useContext();
197
+ return () => <p>{theme}</p>;
198
+ });
199
+ ```
200
+
201
+ ## Portal
202
+
203
+ ```tsx
204
+ import { mount, portal } from 'lithent';
205
+
206
+ const Modal = mount((renew, props: { onClose: () => void }) => {
207
+ return () => portal(
208
+ <div class="modal-overlay" onClick={props.onClose}>
209
+ <div class="modal-content" onClick={(e) => e.stopPropagation()}>
210
+ <h2>Modal</h2>
211
+ <button onClick={props.onClose}>Close</button>
212
+ </div>
213
+ </div>,
214
+ document.body
215
+ );
216
+ });
217
+ ```
218
+
219
+ ## List Rendering
220
+
221
+ Always use `key` prop for lists:
222
+
223
+ ```tsx
224
+ import { mount } from 'lithent';
225
+ import { state } from 'lithent/helper';
226
+
227
+ const TodoList = mount((renew) => {
228
+ const todos = state([
229
+ { id: 1, text: 'Learn Lithent', done: false },
230
+ { id: 2, text: 'Build app', done: false },
231
+ ], renew);
232
+
233
+ const toggle = (id: number) => {
234
+ todos.value = todos.value.map(t =>
235
+ t.id === id ? { ...t, done: !t.done } : t
236
+ );
237
+ };
238
+
239
+ return () => (
240
+ <ul>
241
+ {todos.value.map(todo => (
242
+ <li key={todo.id} onClick={() => toggle(todo.id)}>
243
+ {todo.text} {todo.done && '✓'}
244
+ </li>
245
+ ))}
246
+ </ul>
247
+ );
248
+ });
249
+ ```
250
+
251
+ ## SSR and Hydration
252
+
253
+ ```tsx
254
+ // Server
255
+ import { renderToString } from 'lithent/ssr';
256
+ const html = renderToString(<App />);
257
+
258
+ // Client (hydrate existing DOM)
259
+ import { render } from 'lithent';
260
+ import { hydration } from 'lithent/ssr';
261
+ render(<App />, document.getElementById('app')!, hydration);
262
+ ```
263
+
264
+ ## FTags (No JSX)
265
+
266
+ ```ts
267
+ import { fTags, fMount } from 'lithent/ftags';
268
+ import { state } from 'lithent/helper';
269
+
270
+ const { div, button, p } = fTags;
271
+
272
+ const Counter = fMount((renew) => {
273
+ const count = state(0, renew);
274
+ return () => div({},
275
+ p({}, `Count: ${count.value}`),
276
+ button({ onClick: () => count.value++ }, '+1')
277
+ );
278
+ });
279
+ ```
280
+
281
+ ## HTM (Tagged Templates)
282
+
283
+ ```ts
284
+ import { lTag } from 'lithent/tag';
285
+ import { mount } from 'lithent';
286
+ import { state } from 'lithent/helper';
287
+
288
+ const html = lTag;
289
+
290
+ const Counter = mount((renew) => {
291
+ const count = state(0, renew);
292
+ return () => html`
293
+ <div>
294
+ <p>Count: ${count.value}</p>
295
+ <button onClick=${() => count.value++}>+1</button>
296
+ </div>
297
+ `;
298
+ });
299
+ ```
300
+
301
+ ## Performance
302
+
303
+ ```tsx
304
+ import { cacheUpdate, nextTickRender } from 'lithent/helper';
305
+
306
+ // Batch multiple state updates into single render
307
+ cacheUpdate(() => {
308
+ a.value = 1;
309
+ b.value = 2;
310
+ c.value = 3;
311
+ });
312
+
313
+ // Defer render to next tick
314
+ nextTickRender(() => {
315
+ items.value = [...items.value, ...newItems];
316
+ });
317
+ ```
318
+
319
+ ## Children Handling
320
+
321
+ ```tsx
322
+ import { mount } from 'lithent';
323
+ import { unwrapChildren } from 'lithent/helper';
324
+
325
+ const Card = mount((renew, props: { title: string }, children) => {
326
+ return () => (
327
+ <div class="card">
328
+ <h3>{props.title}</h3>
329
+ <div class="card-body">{unwrapChildren(children)}</div>
330
+ </div>
331
+ );
332
+ });
333
+
334
+ // Usage
335
+ <Card title="Title"><p>Content</p></Card>
336
+ ```
337
+
338
+ ## Import Reference
339
+
340
+ ```tsx
341
+ // Core
342
+ import {
343
+ mount, lmount, render, h, Fragment, portal,
344
+ ref, nextTick, mountCallback, updateCallback, mountReadyCallback
345
+ } from 'lithent';
346
+
347
+ // Helper
348
+ import {
349
+ state, lstate, // Reactive state
350
+ computed, effect, // Derived values & side effects
351
+ store, lstore, // Global state
352
+ createContext, createLContext, // Context API
353
+ cacheUpdate, nextTickRender, // Performance
354
+ unwrapChildren // Utility
355
+ } from 'lithent/helper';
356
+
357
+ // SSR
358
+ import { renderToString, hydration } from 'lithent/ssr';
359
+
360
+ // FTags
361
+ import { fTags, fFragment, fMount } from 'lithent/ftags';
362
+
363
+ // HTM
364
+ import { lTag } from 'lithent/tag';
365
+ ```