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.
- package/dist/lithent-agent-addon.md +126 -0
- package/dist/lithent-skills.md +365 -0
- package/dist/lithent.mjs +157 -165
- package/dist/lithent.mjs.map +1 -1
- package/dist/lithent.umd.js +1 -1
- package/dist/lithent.umd.js.map +1 -1
- package/examples/dist/assets/index-CLyQ20Qs.js +2 -0
- package/examples/dist/assets/index-CLyQ20Qs.js.map +1 -0
- package/examples/dist/index.html +1 -1
- package/package.json +3 -2
- package/src/tests/core-nullUpdater.test.tsx +60 -1
- package/src/wDom.ts +5 -32
- package/ssr/package.json +1 -1
- package/examples/dist/assets/index-DYJGSNhf.js +0 -2
- package/examples/dist/assets/index-DYJGSNhf.js.map +0 -1
|
@@ -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
|
+
```
|