@relax.js/core 1.0.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/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/DataLoader.d.ts +51 -0
- package/dist/DependencyInjection.d.ts +271 -0
- package/dist/DependencyInjectionOld.d.ts +35 -0
- package/dist/Metadata.d.ts +8 -0
- package/dist/SequentialId.d.ts +47 -0
- package/dist/_alt/src/MustardEngine.d.ts +30 -0
- package/dist/_alt/src/MustardParser.d.ts +63 -0
- package/dist/_alt/src/MustardParser2.d.ts +35 -0
- package/dist/_alt/src/pipes.d.ts +93 -0
- package/dist/_alt/src/template.d.ts +166 -0
- package/dist/_alt/src/tools.d.ts +4 -0
- package/dist/_alt/tests/pipes.tests.d.ts +1 -0
- package/dist/_alt/tests/template.tests.d.ts +1 -0
- package/dist/_alt/vitest.config.d.ts +2 -0
- package/dist/collections/Index.d.ts +1 -0
- package/dist/collections/LinkedList.d.ts +75 -0
- package/dist/collections/Pager.d.ts +15 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +7 -0
- package/dist/collections/index.mjs +2 -0
- package/dist/collections/index.mjs.map +7 -0
- package/dist/components/Table.d.ts +13 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +128 -0
- package/dist/components/index.js.map +7 -0
- package/dist/components/index.mjs +128 -0
- package/dist/components/index.mjs.map +7 -0
- package/dist/components/lists/Table.d.ts +59 -0
- package/dist/components/lists/TreeView.d.ts +67 -0
- package/dist/components/lists/index.d.ts +2 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/menus/MenuItem.d.ts +30 -0
- package/dist/components/menus/TopMenu.d.ts +16 -0
- package/dist/components/menus/index.d.ts +2 -0
- package/dist/components/panels/tabs.d.ts +15 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.js +2 -0
- package/dist/di/index.js.map +7 -0
- package/dist/di/index.mjs +2 -0
- package/dist/di/index.mjs.map +7 -0
- package/dist/elements/CopyAttributes.d.ts +2 -0
- package/dist/elements/dom.d.ts +18 -0
- package/dist/elements/index.d.ts +2 -0
- package/dist/elements/index.js +2 -0
- package/dist/elements/index.js.map +7 -0
- package/dist/elements/index.mjs +2 -0
- package/dist/elements/index.mjs.map +7 -0
- package/dist/errors.d.ts +71 -0
- package/dist/forms/FormReader.d.ts +182 -0
- package/dist/forms/FormValidator.d.ts +114 -0
- package/dist/forms/ValidationRules.d.ts +103 -0
- package/dist/forms/index.d.ts +4 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +7 -0
- package/dist/forms/index.mjs +2 -0
- package/dist/forms/index.mjs.map +7 -0
- package/dist/forms/setFormData.d.ts +49 -0
- package/dist/getParentComponent.d.ts +43 -0
- package/dist/html/TableRenderer.d.ts +44 -0
- package/dist/html/TreeBinder.d.ts +9 -0
- package/dist/html/html.d.ts +55 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.js +2 -0
- package/dist/html/index.js.map +7 -0
- package/dist/html/index.mjs +2 -0
- package/dist/html/index.mjs.map +7 -0
- package/dist/html/template.d.ts +167 -0
- package/dist/http/ServerSentEvents.d.ts +116 -0
- package/dist/http/SimpleWebSocket.d.ts +153 -0
- package/dist/http/http.d.ts +177 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +2 -0
- package/dist/http/index.js.map +7 -0
- package/dist/http/index.mjs +2 -0
- package/dist/http/index.mjs.map +7 -0
- package/dist/i18n/i18n.d.ts +105 -0
- package/dist/i18n/icu.d.ts +64 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/index.mjs +2 -0
- package/dist/i18n/index.mjs.map +7 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +7 -0
- package/dist/lib/DataLoader.d.ts +51 -0
- package/dist/lib/DependencyInjection.d.ts +271 -0
- package/dist/lib/InvokeParent.d.ts +10 -0
- package/dist/lib/Pipes.d.ts +236 -0
- package/dist/lib/SequentialId.d.ts +47 -0
- package/dist/lib/collections/Index.d.ts +1 -0
- package/dist/lib/collections/LinkedList.d.ts +75 -0
- package/dist/lib/collections/Pager.d.ts +15 -0
- package/dist/lib/collections/TableRenderer.d.ts +44 -0
- package/dist/lib/di/index.d.ts +1 -0
- package/dist/lib/elements/CopyAttributes.d.ts +2 -0
- package/dist/lib/elements/dom.d.ts +18 -0
- package/dist/lib/elements/index.d.ts +2 -0
- package/dist/lib/errors.d.ts +71 -0
- package/dist/lib/forms/FormReader.d.ts +182 -0
- package/dist/lib/forms/FormValidator.d.ts +114 -0
- package/dist/lib/forms/ValidationRules.d.ts +103 -0
- package/dist/lib/forms/index.d.ts +4 -0
- package/dist/lib/forms/setFormData.d.ts +49 -0
- package/dist/lib/getParentComponent.d.ts +43 -0
- package/dist/lib/html/TableRenderer.d.ts +44 -0
- package/dist/lib/html/TreeBinder.d.ts +9 -0
- package/dist/lib/html/html.d.ts +55 -0
- package/dist/lib/html/html2.d.ts +55 -0
- package/dist/lib/html/index.d.ts +5 -0
- package/dist/lib/html/m.d.ts +167 -0
- package/dist/lib/html/m2.d.ts +8 -0
- package/dist/lib/html/m3.d.ts +0 -0
- package/dist/lib/html/template.d.ts +167 -0
- package/dist/lib/http/HttpClient.d.ts +153 -0
- package/dist/lib/http/ServerSentEvents.d.ts +116 -0
- package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
- package/dist/lib/http/http.d.ts +177 -0
- package/dist/lib/http/index.d.ts +3 -0
- package/dist/lib/i18n/i18n.d.ts +105 -0
- package/dist/lib/i18n/icu.d.ts +64 -0
- package/dist/lib/i18n/index.d.ts +2 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/lib/routing/RouteLink.d.ts +7 -0
- package/dist/lib/routing/Routing.d.ts +270 -0
- package/dist/lib/routing/RoutingTarget.d.ts +22 -0
- package/dist/lib/routing/index.d.ts +7 -0
- package/dist/lib/routing/navigation.d.ts +70 -0
- package/dist/lib/routing/routeMatching.d.ts +21 -0
- package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/lib/routing/types.d.ts +130 -0
- package/dist/lib/templates/NodeTemplate.d.ts +38 -0
- package/dist/lib/templates/accessorParser.d.ts +87 -0
- package/dist/lib/templates/parseTemplate.d.ts +6 -0
- package/dist/lib/templates/tokenizer.d.ts +76 -0
- package/dist/lib/tools.d.ts +30 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/pipes.d.ts +236 -0
- package/dist/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/routing/RouteLink.d.ts +7 -0
- package/dist/routing/RoutingTarget.d.ts +22 -0
- package/dist/routing/index.d.ts +7 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +7 -0
- package/dist/routing/index.mjs +5 -0
- package/dist/routing/index.mjs.map +7 -0
- package/dist/routing/navigation.d.ts +70 -0
- package/dist/routing/routeMatching.d.ts +21 -0
- package/dist/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/routing/types.d.ts +130 -0
- package/dist/templates/NodeTemplate.d.ts +38 -0
- package/dist/templates/accessorParser.d.ts +87 -0
- package/dist/templates/parseTemplate.d.ts +6 -0
- package/dist/templates/tokenizer.d.ts +76 -0
- package/dist/tools.d.ts +30 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.mjs +2 -0
- package/dist/utils/index.mjs.map +7 -0
- package/docs/Architecture.md +333 -0
- package/docs/DependencyInjection.md +237 -0
- package/docs/Errors.md +87 -0
- package/docs/GettingStarted.md +231 -0
- package/docs/Pipes.md +211 -0
- package/docs/Translations.md +312 -0
- package/docs/WhyRelaxjs.md +336 -0
- package/docs/elements/dom.md +102 -0
- package/docs/forms/creating-form-components.md +924 -0
- package/docs/forms/form-api.md +94 -0
- package/docs/forms/forms.md +99 -0
- package/docs/forms/patterns.md +311 -0
- package/docs/forms/reading-writing.md +365 -0
- package/docs/forms/validation.md +351 -0
- package/docs/html/TableRenderer.md +292 -0
- package/docs/html/html.md +175 -0
- package/docs/html/index.md +54 -0
- package/docs/html/template.md +422 -0
- package/docs/http/HttpClient.md +459 -0
- package/docs/http/ServerSentEvents.md +184 -0
- package/docs/http/index.md +109 -0
- package/docs/i18n/i18n.md +309 -0
- package/docs/i18n/intl-standard.md +178 -0
- package/docs/routing/RouteLink.md +98 -0
- package/docs/routing/Routing.md +332 -0
- package/docs/routing/RoutingTarget.md +136 -0
- package/docs/routing/layouts.md +207 -0
- package/docs/utilities.md +143 -0
- package/package.json +93 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# compileTemplate
|
|
2
|
+
|
|
3
|
+
A full-featured template engine for web components. Compiles HTML templates with mustache-style expressions into reactive render functions.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Text Interpolation** - `{{expression}}` syntax with nested path support
|
|
8
|
+
- **Attribute Binding** - Dynamic attribute values
|
|
9
|
+
- **Pipes** - Transform values with `{{value | uppercase | shorten:20}}`
|
|
10
|
+
- **Function Calls** - `{{formatDate(createdAt)}}`, `{{add(5, 3)}}`
|
|
11
|
+
- **Array Indexing** - `{{items[0]}}`, `{{users[1].name}}`
|
|
12
|
+
- **Conditional Rendering** - `if` and `unless` attributes
|
|
13
|
+
- **Loop Rendering** - `loop="item in items"` directive
|
|
14
|
+
- **Type-Safe** - Full TypeScript support
|
|
15
|
+
- **Performance Optimized** - Expression caching and memoized re-renders
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { compileTemplate } from 'relaxjs/html';
|
|
21
|
+
|
|
22
|
+
// 1. Compile the template
|
|
23
|
+
const { content, render } = compileTemplate(`
|
|
24
|
+
<div class="user-card">
|
|
25
|
+
<h2>Hello, {{user.name}}</h2>
|
|
26
|
+
<p if="user.isAdmin">Admin User</p>
|
|
27
|
+
<ul>
|
|
28
|
+
<li loop="permission in user.permissions">{{permission}}</li>
|
|
29
|
+
</ul>
|
|
30
|
+
</div>
|
|
31
|
+
`);
|
|
32
|
+
|
|
33
|
+
// 2. Render with data
|
|
34
|
+
render({
|
|
35
|
+
user: {
|
|
36
|
+
name: 'John Smith',
|
|
37
|
+
isAdmin: true,
|
|
38
|
+
permissions: ['read', 'write', 'delete']
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 3. Append to DOM
|
|
43
|
+
document.getElementById('app').appendChild(content);
|
|
44
|
+
|
|
45
|
+
// 4. Update with new data (DOM updates automatically)
|
|
46
|
+
render({
|
|
47
|
+
user: {
|
|
48
|
+
name: 'Jane Doe',
|
|
49
|
+
isAdmin: false,
|
|
50
|
+
permissions: ['read']
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Template Syntax
|
|
56
|
+
|
|
57
|
+
### Text Interpolation
|
|
58
|
+
|
|
59
|
+
Embed data expressions in text nodes:
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<p>Hello, {{user.name}}! Your score is {{user.score}}.</p>
|
|
63
|
+
<p>Welcome to {{app.name}} - {{app.version}}</p>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Attribute Binding
|
|
67
|
+
|
|
68
|
+
Set attribute values dynamically:
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<img src="/avatars/{{user.id}}.png" alt="Avatar for {{user.name}}">
|
|
72
|
+
<a href="/users/{{user.id}}" class="{{linkClass}}">View Profile</a>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Array Indexing
|
|
76
|
+
|
|
77
|
+
Access array elements by index:
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<p>First item: {{items[0]}}</p>
|
|
81
|
+
<p>Second user: {{users[1].name}}</p>
|
|
82
|
+
<p>Nested: {{data.rows[0].cells[1].value}}</p>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Pipes
|
|
86
|
+
|
|
87
|
+
Transform values using pipe functions:
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<span>{{name | uppercase}}</span>
|
|
91
|
+
<span>{{price | currency}}</span>
|
|
92
|
+
<span>{{text | trim | uppercase | shorten:20}}</span>
|
|
93
|
+
<span>{{createdAt | daysAgo}}</span>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
See [Pipes](../Pipes.md) for the full list of built-in pipes.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { compileTemplate } from 'relaxjs/html';
|
|
100
|
+
import { createPipeRegistry } from 'relaxjs/utils';
|
|
101
|
+
|
|
102
|
+
const pipeRegistry = createPipeRegistry();
|
|
103
|
+
const { content, render } = compileTemplate(
|
|
104
|
+
'<span>{{name | uppercase}}</span>',
|
|
105
|
+
{ strict: false, pipeRegistry }
|
|
106
|
+
);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Function Calls
|
|
110
|
+
|
|
111
|
+
Call functions defined in the functions context:
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<span>Today: {{getDate()}}</span>
|
|
115
|
+
<span>Sum: {{add(5, 3)}}</span>
|
|
116
|
+
<span>{{greet("World")}}</span>
|
|
117
|
+
<span>{{formatPrice(item.price)}}</span>
|
|
118
|
+
<span>{{format(user.name, "bold")}}</span>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const { content, render } = compileTemplate(`
|
|
123
|
+
<div>
|
|
124
|
+
<p>{{formatDate(createdAt)}}</p>
|
|
125
|
+
<p>Total: {{calculateTotal(items)}}</p>
|
|
126
|
+
</div>
|
|
127
|
+
`);
|
|
128
|
+
|
|
129
|
+
render(
|
|
130
|
+
{ createdAt: new Date(), items: [10, 20, 30] },
|
|
131
|
+
{
|
|
132
|
+
formatDate: (d) => d.toLocaleDateString(),
|
|
133
|
+
calculateTotal: (arr) => arr.reduce((a, b) => a + b, 0)
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Function arguments can be:
|
|
139
|
+
- String literals: `"hello"` or `'hello'`
|
|
140
|
+
- Number literals: `42`, `3.14`
|
|
141
|
+
- Context paths: `user.name`, `items[0]`
|
|
142
|
+
|
|
143
|
+
### Conditional Rendering
|
|
144
|
+
|
|
145
|
+
Show or hide elements with the `if` and `unless` directive attributes.
|
|
146
|
+
When hidden, the element is removed from the DOM entirely and replaced by an invisible comment placeholder.
|
|
147
|
+
When shown again, a fresh clone is inserted and its inner bindings are re-compiled with the latest data.
|
|
148
|
+
|
|
149
|
+
#### `if`
|
|
150
|
+
|
|
151
|
+
Renders the element only when the expression resolves to a truthy value:
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<div if="user.isLoggedIn">
|
|
155
|
+
Welcome back, {{user.name}}!
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<button if="cart.items">Checkout</button>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `unless`
|
|
162
|
+
|
|
163
|
+
The inverse of `if`. Renders the element only when the expression is falsy:
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<div unless="user.isLoggedIn">
|
|
167
|
+
Please <a href="/login">sign in</a> to continue.
|
|
168
|
+
</div>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Truthiness Rules
|
|
172
|
+
|
|
173
|
+
The condition expression is resolved from the context and evaluated with JavaScript truthiness:
|
|
174
|
+
|
|
175
|
+
| Value | `if` shows? | `unless` shows? |
|
|
176
|
+
|-------|-------------|-----------------|
|
|
177
|
+
| `true` | yes | no |
|
|
178
|
+
| `false` | no | yes |
|
|
179
|
+
| `"hello"` (non-empty string) | yes | no |
|
|
180
|
+
| `""` (empty string) | no | yes |
|
|
181
|
+
| `1` (positive number) | yes | no |
|
|
182
|
+
| `0` | no | yes |
|
|
183
|
+
| `undefined` / missing | no | yes |
|
|
184
|
+
| `null` | no | yes |
|
|
185
|
+
| `{ ... }` (object) | yes | no |
|
|
186
|
+
|
|
187
|
+
#### Updates Across Renders
|
|
188
|
+
|
|
189
|
+
The element toggles in and out of the DOM as the condition changes across `render()` calls.
|
|
190
|
+
|
|
191
|
+
Inner bindings (text, attributes, nested conditionals, loops) are re-evaluated on every `render()` call while the element is visible, not just when first inserted:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const { content, render } = compileTemplate(`
|
|
195
|
+
<span if="show">{{name}}</span>
|
|
196
|
+
`);
|
|
197
|
+
|
|
198
|
+
render({ show: true, name: 'Alice' });
|
|
199
|
+
// → <span>Alice</span>
|
|
200
|
+
|
|
201
|
+
render({ show: false, name: 'Alice' });
|
|
202
|
+
// → (element removed)
|
|
203
|
+
|
|
204
|
+
render({ show: true, name: 'Bob' });
|
|
205
|
+
// → <span>Bob</span> (picks up latest data)
|
|
206
|
+
|
|
207
|
+
render({ show: true, name: 'Charlie' });
|
|
208
|
+
// → <span>Charlie</span> (inner content updates while visible)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### Nesting Conditionals
|
|
212
|
+
|
|
213
|
+
`if` and `unless` can be nested. Inner conditionals react independently to their own expressions:
|
|
214
|
+
|
|
215
|
+
```html
|
|
216
|
+
<div if="hasPermission">
|
|
217
|
+
<p>You have access.</p>
|
|
218
|
+
<div if="isAdmin">
|
|
219
|
+
<button>Delete All</button>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
render({ hasPermission: true, isAdmin: true });
|
|
226
|
+
// → both div and button visible
|
|
227
|
+
|
|
228
|
+
render({ hasPermission: true, isAdmin: false });
|
|
229
|
+
// → outer div visible, button removed
|
|
230
|
+
|
|
231
|
+
render({ hasPermission: false, isAdmin: true });
|
|
232
|
+
// → everything removed (outer controls inner)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Multiple Independent Conditionals
|
|
236
|
+
|
|
237
|
+
Sibling `if` elements toggle independently and preserve their position among siblings:
|
|
238
|
+
|
|
239
|
+
```html
|
|
240
|
+
<span>Always</span>
|
|
241
|
+
<span if="showA">A</span>
|
|
242
|
+
<span if="showB">B</span>
|
|
243
|
+
<span>End</span>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Loop Rendering
|
|
247
|
+
|
|
248
|
+
Repeat elements for arrays with `loop`:
|
|
249
|
+
|
|
250
|
+
```html
|
|
251
|
+
<ul>
|
|
252
|
+
<li loop="item in cart.items">
|
|
253
|
+
{{item.name}} - ${{item.price}}
|
|
254
|
+
</li>
|
|
255
|
+
</ul>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Combine with conditionals:
|
|
259
|
+
|
|
260
|
+
```html
|
|
261
|
+
<table>
|
|
262
|
+
<tr loop="user in users">
|
|
263
|
+
<td>{{user.name}}</td>
|
|
264
|
+
<td if="user.isAdmin">Administrator</td>
|
|
265
|
+
<td unless="user.isAdmin">Regular User</td>
|
|
266
|
+
</tr>
|
|
267
|
+
</table>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Loop with array indexing:
|
|
271
|
+
|
|
272
|
+
```html
|
|
273
|
+
<li loop="item in data.lists[0]">{{item}}</li>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Configuration
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { compileTemplate, EngineConfig } from 'relaxjs/html';
|
|
280
|
+
import { createPipeRegistry } from 'relaxjs/utils';
|
|
281
|
+
|
|
282
|
+
const config: EngineConfig = {
|
|
283
|
+
strict: true,
|
|
284
|
+
onError: (msg) => console.error(msg),
|
|
285
|
+
pipeRegistry: createPipeRegistry()
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const { content, render } = compileTemplate(template, config);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
| Option | Type | Default | Description |
|
|
292
|
+
|--------|------|---------|-------------|
|
|
293
|
+
| `strict` | boolean | `false` | Throw errors for missing paths/functions |
|
|
294
|
+
| `onError` | function | `undefined` | Callback for error messages |
|
|
295
|
+
| `pipeRegistry` | PipeRegistry | `defaultPipes` | Custom pipe registry |
|
|
296
|
+
|
|
297
|
+
## API Reference
|
|
298
|
+
|
|
299
|
+
### compileTemplate(templateStr, config?)
|
|
300
|
+
|
|
301
|
+
Compiles an HTML template string into a render function.
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
function compileTemplate(
|
|
305
|
+
templateStr: string,
|
|
306
|
+
config?: EngineConfig
|
|
307
|
+
): CompiledTemplate;
|
|
308
|
+
|
|
309
|
+
interface CompiledTemplate {
|
|
310
|
+
content: DocumentFragment | HTMLElement;
|
|
311
|
+
render: (ctx: Context, fns?: FunctionsContext) => void;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Context
|
|
316
|
+
|
|
317
|
+
Data object passed to `render()`:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
interface Context {
|
|
321
|
+
[key: string]: ContextValue;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Example
|
|
325
|
+
render({
|
|
326
|
+
user: { name: 'John', age: 30 },
|
|
327
|
+
items: ['a', 'b', 'c'],
|
|
328
|
+
isActive: true
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### FunctionsContext
|
|
333
|
+
|
|
334
|
+
Functions object passed as second argument to `render()`:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
interface FunctionsContext {
|
|
338
|
+
[key: string]: (...args: any[]) => any;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Example
|
|
342
|
+
render(data, {
|
|
343
|
+
formatDate: (d) => d.toLocaleDateString(),
|
|
344
|
+
add: (a, b) => a + b,
|
|
345
|
+
greet: (name) => `Hello, ${name}!`
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Web Component Integration
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
class UserCard extends HTMLElement {
|
|
353
|
+
private template: CompiledTemplate;
|
|
354
|
+
private _user: any = null;
|
|
355
|
+
|
|
356
|
+
constructor() {
|
|
357
|
+
super();
|
|
358
|
+
this.attachShadow({ mode: 'open' });
|
|
359
|
+
|
|
360
|
+
this.template = compileTemplate(`
|
|
361
|
+
<div class="card">
|
|
362
|
+
<h3>{{user.name}}</h3>
|
|
363
|
+
<p>{{user.email}}</p>
|
|
364
|
+
<p if="user.isAdmin">Administrator</p>
|
|
365
|
+
</div>
|
|
366
|
+
`);
|
|
367
|
+
|
|
368
|
+
this.shadowRoot!.appendChild(this.template.content);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
set user(value) {
|
|
372
|
+
this._user = value;
|
|
373
|
+
this.template.render({ user: this._user });
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
customElements.define('user-card', UserCard);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Complete Example
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import { compileTemplate } from 'relaxjs/html';
|
|
384
|
+
import { createPipeRegistry } from 'relaxjs/utils';
|
|
385
|
+
|
|
386
|
+
const pipeRegistry = createPipeRegistry();
|
|
387
|
+
|
|
388
|
+
const { content, render } = compileTemplate(`
|
|
389
|
+
<div class="product-list">
|
|
390
|
+
<h1>{{title | uppercase}}</h1>
|
|
391
|
+
<p if="showIntro">{{getIntro()}}</p>
|
|
392
|
+
|
|
393
|
+
<ul>
|
|
394
|
+
<li loop="product in products" if="product.inStock">
|
|
395
|
+
<span>{{product.name | capitalize}}</span>
|
|
396
|
+
<span>{{formatPrice(product.price)}}</span>
|
|
397
|
+
<span>{{product.stock}} in stock</span>
|
|
398
|
+
</li>
|
|
399
|
+
</ul>
|
|
400
|
+
|
|
401
|
+
<p unless="products">No products available</p>
|
|
402
|
+
</div>
|
|
403
|
+
`, { strict: false, pipeRegistry });
|
|
404
|
+
|
|
405
|
+
render(
|
|
406
|
+
{
|
|
407
|
+
title: 'our products',
|
|
408
|
+
showIntro: true,
|
|
409
|
+
products: [
|
|
410
|
+
{ name: 'apple', price: 1.50, stock: 10, inStock: true },
|
|
411
|
+
{ name: 'banana', price: 0.75, stock: 0, inStock: false },
|
|
412
|
+
{ name: 'orange', price: 2.00, stock: 5, inStock: true }
|
|
413
|
+
]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
getIntro: () => 'Welcome to our store!',
|
|
417
|
+
formatPrice: (p) => `$${p.toFixed(2)}`
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
document.body.appendChild(content);
|
|
422
|
+
```
|