@vertz/ui-server 0.2.0
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 +455 -0
- package/dist/dom-shim/index.d.ts +84 -0
- package/dist/dom-shim/index.js +332 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.js +403 -0
- package/dist/jsx-runtime/index.d.ts +39 -0
- package/dist/jsx-runtime/index.js +61 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# @vertz/ui-server
|
|
2
|
+
|
|
3
|
+
Server-side rendering (SSR) for `@vertz/ui`.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Streaming HTML** — `renderToStream()` returns a `ReadableStream<Uint8Array>`
|
|
8
|
+
- **Out-of-order streaming** — Suspense boundaries emit placeholders immediately, resolved content later
|
|
9
|
+
- **Atomic hydration markers** — Interactive components get `data-v-id` attributes; static components ship zero JS
|
|
10
|
+
- **Head management** — Collect `<title>`, `<meta>`, and `<link>` tags during render
|
|
11
|
+
- **Asset injection** — Script and stylesheet helpers for the HTML head
|
|
12
|
+
- **Critical CSS inlining** — Inline above-the-fold CSS with injection prevention
|
|
13
|
+
- **CSP nonce support** — All inline scripts support Content Security Policy nonces
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @vertz/ui-server
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Basic SSR
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { renderToStream } from '@vertz/ui-server';
|
|
27
|
+
import type { VNode } from '@vertz/ui-server';
|
|
28
|
+
|
|
29
|
+
const tree: VNode = {
|
|
30
|
+
tag: 'html',
|
|
31
|
+
attrs: { lang: 'en' },
|
|
32
|
+
children: [
|
|
33
|
+
{
|
|
34
|
+
tag: 'head',
|
|
35
|
+
attrs: {},
|
|
36
|
+
children: [{ tag: 'title', attrs: {}, children: ['My App'] }],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
tag: 'body',
|
|
40
|
+
attrs: {},
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
tag: 'div',
|
|
44
|
+
attrs: { id: 'app' },
|
|
45
|
+
children: ['Hello, SSR!'],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const stream = renderToStream(tree);
|
|
53
|
+
|
|
54
|
+
// Return as HTTP response
|
|
55
|
+
return new Response(stream, {
|
|
56
|
+
headers: { 'content-type': 'text/html; charset=utf-8' },
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Streaming with Suspense
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { renderToStream } from '@vertz/ui-server';
|
|
64
|
+
import type { VNode } from '@vertz/ui-server';
|
|
65
|
+
|
|
66
|
+
// Create a Suspense boundary
|
|
67
|
+
const suspenseNode = {
|
|
68
|
+
tag: '__suspense',
|
|
69
|
+
attrs: {},
|
|
70
|
+
children: [],
|
|
71
|
+
_fallback: { tag: 'div', attrs: { class: 'skeleton' }, children: ['Loading...'] },
|
|
72
|
+
_resolve: fetchUserData().then((user) => ({
|
|
73
|
+
tag: 'div',
|
|
74
|
+
attrs: { class: 'user-profile' },
|
|
75
|
+
children: [user.name],
|
|
76
|
+
})),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const tree: VNode = {
|
|
80
|
+
tag: 'div',
|
|
81
|
+
attrs: { id: 'app' },
|
|
82
|
+
children: [
|
|
83
|
+
{ tag: 'h1', attrs: {}, children: ['User Profile'] },
|
|
84
|
+
suspenseNode as VNode,
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const stream = renderToStream(tree);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**How out-of-order streaming works:**
|
|
92
|
+
|
|
93
|
+
1. The initial stream contains the placeholder: `<div id="v-slot-0"><div class="skeleton">Loading...</div></div>`
|
|
94
|
+
2. When `_resolve` completes, a replacement chunk is streamed:
|
|
95
|
+
```html
|
|
96
|
+
<template id="v-tmpl-0"><div class="user-profile">Alice</div></template>
|
|
97
|
+
<script>
|
|
98
|
+
(function(){
|
|
99
|
+
var s=document.getElementById("v-slot-0");
|
|
100
|
+
var t=document.getElementById("v-tmpl-0");
|
|
101
|
+
if(s&&t){s.replaceWith(t.content.cloneNode(true));t.remove()}
|
|
102
|
+
})()
|
|
103
|
+
</script>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### CSP Nonce Support
|
|
107
|
+
|
|
108
|
+
For sites with strict Content Security Policies:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { renderToStream } from '@vertz/ui-server';
|
|
112
|
+
|
|
113
|
+
const nonce = crypto.randomUUID();
|
|
114
|
+
|
|
115
|
+
const stream = renderToStream(tree, { nonce });
|
|
116
|
+
|
|
117
|
+
return new Response(stream, {
|
|
118
|
+
headers: {
|
|
119
|
+
'content-type': 'text/html; charset=utf-8',
|
|
120
|
+
'content-security-policy': `script-src 'nonce-${nonce}'`,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
All inline `<script>` tags (Suspense replacement scripts) will include `nonce="..."`.
|
|
126
|
+
|
|
127
|
+
### Hydration Markers
|
|
128
|
+
|
|
129
|
+
Interactive components get hydration markers so the client knows where to attach event handlers:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { wrapWithHydrationMarkers } from '@vertz/ui-server';
|
|
133
|
+
import type { VNode } from '@vertz/ui-server';
|
|
134
|
+
|
|
135
|
+
const counterNode: VNode = {
|
|
136
|
+
tag: 'div',
|
|
137
|
+
attrs: {},
|
|
138
|
+
children: [
|
|
139
|
+
{ tag: 'span', attrs: {}, children: ['Count: 0'] },
|
|
140
|
+
{ tag: 'button', attrs: {}, children: ['+'] },
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const hydratedNode = wrapWithHydrationMarkers(counterNode, {
|
|
145
|
+
componentName: 'Counter',
|
|
146
|
+
key: 'counter-0',
|
|
147
|
+
props: { initial: 0 },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const stream = renderToStream(hydratedNode);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Output:**
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<div data-v-id="Counter" data-v-key="counter-0">
|
|
157
|
+
<span>Count: 0</span>
|
|
158
|
+
<button>+</button>
|
|
159
|
+
<script type="application/json">{"initial":0}</script>
|
|
160
|
+
</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The hydration runtime on the client reads `data-v-id` and `data-v-key` to restore interactivity.
|
|
164
|
+
|
|
165
|
+
### Head Management
|
|
166
|
+
|
|
167
|
+
Collect `<title>`, `<meta>`, and `<link>` tags during render:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { HeadCollector, renderHeadToHtml, rawHtml } from '@vertz/ui-server';
|
|
171
|
+
|
|
172
|
+
const headCollector = new HeadCollector();
|
|
173
|
+
headCollector.addTitle('My SSR App');
|
|
174
|
+
headCollector.addMeta({ charset: 'utf-8' });
|
|
175
|
+
headCollector.addMeta({ name: 'viewport', content: 'width=device-width, initial-scale=1' });
|
|
176
|
+
headCollector.addLink({ rel: 'stylesheet', href: '/styles.css' });
|
|
177
|
+
|
|
178
|
+
const headHtml = renderHeadToHtml(headCollector.getEntries());
|
|
179
|
+
|
|
180
|
+
const tree: VNode = {
|
|
181
|
+
tag: 'html',
|
|
182
|
+
attrs: { lang: 'en' },
|
|
183
|
+
children: [
|
|
184
|
+
{
|
|
185
|
+
tag: 'head',
|
|
186
|
+
attrs: {},
|
|
187
|
+
children: [rawHtml(headHtml)],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
tag: 'body',
|
|
191
|
+
attrs: {},
|
|
192
|
+
children: [{ tag: 'div', attrs: { id: 'app' }, children: ['Content'] }],
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const stream = renderToStream(tree);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Asset Injection
|
|
201
|
+
|
|
202
|
+
Inject scripts and stylesheets into the HTML head:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { renderAssetTags } from '@vertz/ui-server';
|
|
206
|
+
import type { AssetDescriptor } from '@vertz/ui-server';
|
|
207
|
+
|
|
208
|
+
const assets: AssetDescriptor[] = [
|
|
209
|
+
{ type: 'stylesheet', src: '/styles/main.css' },
|
|
210
|
+
{ type: 'script', src: '/js/runtime.js', defer: true },
|
|
211
|
+
{ type: 'script', src: '/js/app.js', defer: true },
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
const assetHtml = renderAssetTags(assets);
|
|
215
|
+
// <link rel="stylesheet" href="/styles/main.css">
|
|
216
|
+
// <script src="/js/runtime.js" defer></script>
|
|
217
|
+
// <script src="/js/app.js" defer></script>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Critical CSS Inlining
|
|
221
|
+
|
|
222
|
+
Inline above-the-fold CSS for faster First Contentful Paint:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { inlineCriticalCss, rawHtml } from '@vertz/ui-server';
|
|
226
|
+
|
|
227
|
+
const criticalCss = `
|
|
228
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
229
|
+
.hero { padding: 2rem; background: linear-gradient(to right, #667eea, #764ba2); }
|
|
230
|
+
`;
|
|
231
|
+
|
|
232
|
+
const styleTag = inlineCriticalCss(criticalCss);
|
|
233
|
+
// <style>body { margin: 0; font-family: system-ui, sans-serif; } ...</style>
|
|
234
|
+
|
|
235
|
+
const tree: VNode = {
|
|
236
|
+
tag: 'html',
|
|
237
|
+
attrs: {},
|
|
238
|
+
children: [
|
|
239
|
+
{
|
|
240
|
+
tag: 'head',
|
|
241
|
+
attrs: {},
|
|
242
|
+
children: [rawHtml(styleTag)],
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
tag: 'body',
|
|
246
|
+
attrs: {},
|
|
247
|
+
children: [{ tag: 'div', attrs: { class: 'hero' }, children: ['Hero Section'] }],
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const stream = renderToStream(tree);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The `inlineCriticalCss()` function escapes any `</style>` sequences in the CSS to prevent injection attacks.
|
|
256
|
+
|
|
257
|
+
### Raw HTML
|
|
258
|
+
|
|
259
|
+
Embed pre-rendered HTML without escaping:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { rawHtml } from '@vertz/ui-server';
|
|
263
|
+
import type { VNode } from '@vertz/ui-server';
|
|
264
|
+
|
|
265
|
+
const tree: VNode = {
|
|
266
|
+
tag: 'div',
|
|
267
|
+
attrs: {},
|
|
268
|
+
children: [
|
|
269
|
+
rawHtml('<p>This HTML is <strong>not</strong> escaped.</p>'),
|
|
270
|
+
'This text is escaped.',
|
|
271
|
+
],
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const stream = renderToStream(tree);
|
|
275
|
+
// <div><p>This HTML is <strong>not</strong> escaped.</p>This text is escaped.</div>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Warning:** Only use `rawHtml()` with trusted content. Embedding user-generated content without escaping is a security risk.
|
|
279
|
+
|
|
280
|
+
## API Reference
|
|
281
|
+
|
|
282
|
+
### `renderToStream(tree, options?)`
|
|
283
|
+
|
|
284
|
+
Render a VNode tree to a `ReadableStream<Uint8Array>`.
|
|
285
|
+
|
|
286
|
+
- **Parameters:**
|
|
287
|
+
- `tree: VNode | string | RawHtml` — The virtual tree to render
|
|
288
|
+
- `options?: RenderToStreamOptions` — Optional configuration
|
|
289
|
+
- `nonce?: string` — CSP nonce for inline scripts
|
|
290
|
+
- **Returns:** `ReadableStream<Uint8Array>`
|
|
291
|
+
|
|
292
|
+
### `wrapWithHydrationMarkers(node, options)`
|
|
293
|
+
|
|
294
|
+
Wrap a VNode with hydration markers for interactive components.
|
|
295
|
+
|
|
296
|
+
- **Parameters:**
|
|
297
|
+
- `node: VNode` — The component's root VNode
|
|
298
|
+
- `options: HydrationOptions`
|
|
299
|
+
- `componentName: string` — Component name for `data-v-id`
|
|
300
|
+
- `key: string` — Unique key for `data-v-key`
|
|
301
|
+
- `props?: Record<string, unknown>` — Serialized props
|
|
302
|
+
- **Returns:** `VNode` — A new VNode with hydration attributes
|
|
303
|
+
|
|
304
|
+
### `HeadCollector`
|
|
305
|
+
|
|
306
|
+
Collects `<head>` metadata during SSR.
|
|
307
|
+
|
|
308
|
+
- **Methods:**
|
|
309
|
+
- `addTitle(text: string)` — Add a `<title>` tag
|
|
310
|
+
- `addMeta(attrs: Record<string, string>)` — Add a `<meta>` tag
|
|
311
|
+
- `addLink(attrs: Record<string, string>)` — Add a `<link>` tag
|
|
312
|
+
- `getEntries(): HeadEntry[]` — Get all collected entries
|
|
313
|
+
- `clear()` — Clear all entries
|
|
314
|
+
|
|
315
|
+
### `renderHeadToHtml(entries)`
|
|
316
|
+
|
|
317
|
+
Render head entries to an HTML string.
|
|
318
|
+
|
|
319
|
+
- **Parameters:**
|
|
320
|
+
- `entries: HeadEntry[]` — Collected head entries
|
|
321
|
+
- **Returns:** `string` — HTML string
|
|
322
|
+
|
|
323
|
+
### `renderAssetTags(assets)`
|
|
324
|
+
|
|
325
|
+
Render asset descriptors to HTML tags.
|
|
326
|
+
|
|
327
|
+
- **Parameters:**
|
|
328
|
+
- `assets: AssetDescriptor[]` — Script/stylesheet descriptors
|
|
329
|
+
- **Returns:** `string` — HTML string
|
|
330
|
+
|
|
331
|
+
### `inlineCriticalCss(css)`
|
|
332
|
+
|
|
333
|
+
Inline critical CSS as a `<style>` tag.
|
|
334
|
+
|
|
335
|
+
- **Parameters:**
|
|
336
|
+
- `css: string` — CSS content
|
|
337
|
+
- **Returns:** `string` — `<style>...</style>` or empty string
|
|
338
|
+
|
|
339
|
+
### `rawHtml(html)`
|
|
340
|
+
|
|
341
|
+
Create a raw HTML string that bypasses escaping.
|
|
342
|
+
|
|
343
|
+
- **Parameters:**
|
|
344
|
+
- `html: string` — Pre-rendered HTML
|
|
345
|
+
- **Returns:** `RawHtml` — Raw HTML object
|
|
346
|
+
|
|
347
|
+
### `serializeToHtml(node)`
|
|
348
|
+
|
|
349
|
+
Serialize a VNode tree to an HTML string (synchronous).
|
|
350
|
+
|
|
351
|
+
- **Parameters:**
|
|
352
|
+
- `node: VNode | string | RawHtml` — The virtual tree to serialize
|
|
353
|
+
- **Returns:** `string` — HTML string
|
|
354
|
+
|
|
355
|
+
### Utilities
|
|
356
|
+
|
|
357
|
+
- `streamToString(stream: ReadableStream<Uint8Array>): Promise<string>` — Convert stream to string (for testing)
|
|
358
|
+
- `collectStreamChunks(stream: ReadableStream<Uint8Array>): Promise<string[]>` — Collect stream chunks as array (for testing)
|
|
359
|
+
- `encodeChunk(html: string): Uint8Array` — Encode string to UTF-8 chunk
|
|
360
|
+
|
|
361
|
+
## Types
|
|
362
|
+
|
|
363
|
+
### `VNode`
|
|
364
|
+
|
|
365
|
+
Virtual node representing an HTML element.
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
interface VNode {
|
|
369
|
+
tag: string;
|
|
370
|
+
attrs: Record<string, string>;
|
|
371
|
+
children: (VNode | string | RawHtml)[];
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### `RawHtml`
|
|
376
|
+
|
|
377
|
+
Raw HTML that bypasses escaping.
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
interface RawHtml {
|
|
381
|
+
__raw: true;
|
|
382
|
+
html: string;
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### `HydrationOptions`
|
|
387
|
+
|
|
388
|
+
Options for hydration marker generation.
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
interface HydrationOptions {
|
|
392
|
+
componentName: string;
|
|
393
|
+
key: string;
|
|
394
|
+
props?: Record<string, unknown>;
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### `HeadEntry`
|
|
399
|
+
|
|
400
|
+
Metadata entry for the HTML head.
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
interface HeadEntry {
|
|
404
|
+
tag: 'title' | 'meta' | 'link';
|
|
405
|
+
attrs?: Record<string, string>;
|
|
406
|
+
textContent?: string;
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### `AssetDescriptor`
|
|
411
|
+
|
|
412
|
+
Asset descriptor for script/stylesheet injection.
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
interface AssetDescriptor {
|
|
416
|
+
type: 'script' | 'stylesheet';
|
|
417
|
+
src: string;
|
|
418
|
+
async?: boolean; // scripts only
|
|
419
|
+
defer?: boolean; // scripts only
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### `RenderToStreamOptions`
|
|
424
|
+
|
|
425
|
+
Options for `renderToStream()`.
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
interface RenderToStreamOptions {
|
|
429
|
+
nonce?: string; // CSP nonce for inline scripts
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Testing
|
|
434
|
+
|
|
435
|
+
Run the test suite:
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
bun run test
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Run tests in watch mode:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
bun run test:watch
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Type check:
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
bun run typecheck
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## License
|
|
454
|
+
|
|
455
|
+
MIT
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** A raw HTML string that bypasses escaping during serialization. */
|
|
2
|
+
interface RawHtml {
|
|
3
|
+
__raw: true;
|
|
4
|
+
html: string;
|
|
5
|
+
}
|
|
6
|
+
/** Virtual node representing an HTML element for SSR serialization. */
|
|
7
|
+
interface VNode {
|
|
8
|
+
tag: string;
|
|
9
|
+
attrs: Record<string, string>;
|
|
10
|
+
children: (VNode | string | RawHtml)[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Base Node class for SSR — matches the browser's Node interface minimally
|
|
14
|
+
*/
|
|
15
|
+
declare class SSRNode {
|
|
16
|
+
childNodes: SSRNode[];
|
|
17
|
+
parentNode: SSRNode | null;
|
|
18
|
+
get firstChild(): SSRNode | null;
|
|
19
|
+
get nextSibling(): SSRNode | null;
|
|
20
|
+
removeChild(child: SSRNode): SSRNode;
|
|
21
|
+
insertBefore(newNode: SSRNode, referenceNode: SSRNode | null): SSRNode;
|
|
22
|
+
replaceChild(newNode: SSRNode, oldNode: SSRNode): SSRNode;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* SSR text node
|
|
26
|
+
*/
|
|
27
|
+
declare class SSRTextNode extends SSRNode {
|
|
28
|
+
text: string;
|
|
29
|
+
constructor(text: string);
|
|
30
|
+
get data(): string;
|
|
31
|
+
set data(value: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* SSR document fragment
|
|
35
|
+
*/
|
|
36
|
+
declare class SSRDocumentFragment extends SSRNode {
|
|
37
|
+
children: (SSRElement | string)[];
|
|
38
|
+
appendChild(child: SSRElement | SSRTextNode | SSRDocumentFragment): void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A VNode-based element that supports basic DOM-like operations.
|
|
42
|
+
*/
|
|
43
|
+
declare class SSRElement extends SSRNode {
|
|
44
|
+
tag: string;
|
|
45
|
+
attrs: Record<string, string>;
|
|
46
|
+
children: (SSRElement | string)[];
|
|
47
|
+
_classList: Set<string>;
|
|
48
|
+
_textContent: string | null;
|
|
49
|
+
_innerHTML: string | null;
|
|
50
|
+
style: Record<string, any>;
|
|
51
|
+
constructor(tag: string);
|
|
52
|
+
setAttribute(name: string, value: string): void;
|
|
53
|
+
getAttribute(name: string): string | null;
|
|
54
|
+
removeAttribute(name: string): void;
|
|
55
|
+
appendChild(child: SSRElement | SSRTextNode | SSRDocumentFragment): void;
|
|
56
|
+
removeChild(child: SSRNode): SSRNode;
|
|
57
|
+
get classList(): {
|
|
58
|
+
add: (cls: string) => void;
|
|
59
|
+
remove: (cls: string) => void;
|
|
60
|
+
};
|
|
61
|
+
set className(value: string);
|
|
62
|
+
get className(): string;
|
|
63
|
+
set textContent(value: string | null);
|
|
64
|
+
get textContent(): string | null;
|
|
65
|
+
set innerHTML(value: string);
|
|
66
|
+
get innerHTML(): string;
|
|
67
|
+
addEventListener(_event: string, _handler: any): void;
|
|
68
|
+
removeEventListener(_event: string, _handler: any): void;
|
|
69
|
+
/** Convert to a VNode tree for @vertz/ui-server */
|
|
70
|
+
toVNode(): VNode;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create and install the DOM shim
|
|
74
|
+
*/
|
|
75
|
+
declare function installDomShim(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Remove the DOM shim
|
|
78
|
+
*/
|
|
79
|
+
declare function removeDomShim(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Convert an SSRElement to a VNode
|
|
82
|
+
*/
|
|
83
|
+
declare function toVNode2(element: any): VNode;
|
|
84
|
+
export { toVNode2 as toVNode, removeDomShim, installDomShim, SSRTextNode, SSRNode, SSRElement, SSRDocumentFragment };
|