@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,292 @@
|
|
|
1
|
+
# TableRenderer for Web Components
|
|
2
|
+
|
|
3
|
+
`TableRenderer` is a small helper class that renders table rows inside Web Components using a `<template>` and an array of data. It supports data binding, row updates, and declarative button handlers that call methods on your Web Component.
|
|
4
|
+
|
|
5
|
+
## ✅ 1. Getting Started
|
|
6
|
+
|
|
7
|
+
### Minimal Web Component Setup
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { TableRenderer } from 'relaxjs/html';
|
|
11
|
+
|
|
12
|
+
class UserTable extends HTMLElement {
|
|
13
|
+
private renderer!: TableRenderer;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.attachShadow({ mode: 'open' });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
connectedCallback() {
|
|
21
|
+
this.shadowRoot!.innerHTML = `
|
|
22
|
+
<table>
|
|
23
|
+
<tbody></tbody>
|
|
24
|
+
</table>
|
|
25
|
+
<template id="row-template">
|
|
26
|
+
<tr>
|
|
27
|
+
<td data-field="name"></td>
|
|
28
|
+
<td data-field="role"></td>
|
|
29
|
+
</tr>
|
|
30
|
+
</template>
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const table = this.shadowRoot!.querySelector('table')!;
|
|
34
|
+
const template = this.shadowRoot!.querySelector('#row-template') as HTMLTemplateElement;
|
|
35
|
+
|
|
36
|
+
this.renderer = new TableRenderer(table, template, 'id', this);
|
|
37
|
+
this.renderer.render([
|
|
38
|
+
{ id: 1, name: 'Alice', role: 'Admin' },
|
|
39
|
+
{ id: 2, name: 'Bob', role: 'User' }
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
customElements.define('user-table', UserTable);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**What this does:**
|
|
48
|
+
- Clones the `<template>` row for each item
|
|
49
|
+
- Fills in `<td data-field="name">` using data values
|
|
50
|
+
- Associates each row with its data via the `id` field
|
|
51
|
+
|
|
52
|
+
## 🛠 2. Updating a Row
|
|
53
|
+
|
|
54
|
+
Use `update()` to refresh a single row without re-rendering everything:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
this.renderer.update({ id: 2, name: 'Bob Smith', role: 'Moderator' });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If a matching row exists (`idColumn` = `"id"`), it will update in-place. If not, a new row is added.
|
|
61
|
+
|
|
62
|
+
## 🎯 3. Button Event Binding
|
|
63
|
+
|
|
64
|
+
Add buttons in the template using `onclick="methodName"`.
|
|
65
|
+
|
|
66
|
+
### Updated Template
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<template id="row-template">
|
|
70
|
+
<tr>
|
|
71
|
+
<td data-field="name"></td>
|
|
72
|
+
<td data-field="role"></td>
|
|
73
|
+
<td>
|
|
74
|
+
<button onclick="edit">Edit</button>
|
|
75
|
+
</td>
|
|
76
|
+
</tr>
|
|
77
|
+
</template>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Component Method
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
edit(data: any, event: MouseEvent) {
|
|
84
|
+
console.log('Editing user:', data);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Behavior:**
|
|
89
|
+
- `edit` is automatically bound for each row
|
|
90
|
+
- It receives the row's `data` as the first argument
|
|
91
|
+
- The second argument is the `MouseEvent`
|
|
92
|
+
|
|
93
|
+
## 📦 4. Using Arguments in Handlers
|
|
94
|
+
|
|
95
|
+
You can call methods with literal arguments. The remaining arguments are always `data` and `event`.
|
|
96
|
+
|
|
97
|
+
### Template Example
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<button onclick="remove('soft')">Delete</button>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Component Method
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
remove(mode: string, data: any, event: MouseEvent) {
|
|
107
|
+
console.log(`Removing (${mode})`, data);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**How It Works:**
|
|
112
|
+
- The string `'soft'` is passed as the first argument
|
|
113
|
+
- `data` and `event` are appended automatically
|
|
114
|
+
|
|
115
|
+
## 🧼 5. Re-rendering Safely
|
|
116
|
+
|
|
117
|
+
The `.render()` method replaces all rows and cleans up memory:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
this.renderer.render([
|
|
121
|
+
{ id: 3, name: 'Charlie', role: 'User' }
|
|
122
|
+
]);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Clears old rows and their event listeners
|
|
126
|
+
- Rebuilds new rows from the template and data
|
|
127
|
+
|
|
128
|
+
## 6. Column Sorting with TableSorter
|
|
129
|
+
|
|
130
|
+
`TableSorter` adds click-to-sort behavior to table headers. Click a `<th>` to cycle through ascending, descending, and unsorted.
|
|
131
|
+
|
|
132
|
+
### Setup
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { TableSorter } from 'relaxjs/html';
|
|
136
|
+
|
|
137
|
+
class UserTable extends HTMLElement {
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
this.innerHTML = `
|
|
140
|
+
<table>
|
|
141
|
+
<thead>
|
|
142
|
+
<tr>
|
|
143
|
+
<th name="name">Name</th>
|
|
144
|
+
<th name="role">Role</th>
|
|
145
|
+
<th name="age">Age</th>
|
|
146
|
+
</tr>
|
|
147
|
+
</thead>
|
|
148
|
+
<tbody></tbody>
|
|
149
|
+
</table>
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
const table = this.querySelector('table')!;
|
|
153
|
+
const sorter = new TableSorter(table, this);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**How it works:**
|
|
159
|
+
- Headers must have a `name` attribute matching the data field
|
|
160
|
+
- Click cycles: none -> ascending (arrow up) -> descending (arrow down) -> none
|
|
161
|
+
- Sort indicators (arrows) are added/removed automatically
|
|
162
|
+
|
|
163
|
+
### Handling Sort Events
|
|
164
|
+
|
|
165
|
+
`TableSorter` dispatches a `SortChangeEvent` on the component:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { SortChangeEvent, SortColumn } from 'relaxjs/html';
|
|
169
|
+
|
|
170
|
+
this.addEventListener('sortchange', (e: SortChangeEvent) => {
|
|
171
|
+
const sortColumns: SortColumn[] = e.detail;
|
|
172
|
+
// sortColumns = [{ column: 'name', direction: 'asc' }]
|
|
173
|
+
this.fetchSortedData(sortColumns);
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### API
|
|
178
|
+
|
|
179
|
+
| Method | Description |
|
|
180
|
+
|--------|-------------|
|
|
181
|
+
| `getSortColumns()` | Returns current sort state as `SortColumn[]` |
|
|
182
|
+
| `clear()` | Resets all sorting and emits a `sortchange` event |
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
type SortColumn = { column: string; direction: 'asc' | 'desc' };
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 7. Pagination with Pager
|
|
189
|
+
|
|
190
|
+
`Pager` renders page navigation buttons (Previous, page numbers, Next) and dispatches events on page change.
|
|
191
|
+
|
|
192
|
+
### Setup
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { Pager, PageSelectedEvent } from 'relaxjs/html';
|
|
196
|
+
|
|
197
|
+
class UserTable extends HTMLElement {
|
|
198
|
+
private pager!: Pager;
|
|
199
|
+
|
|
200
|
+
connectedCallback() {
|
|
201
|
+
this.innerHTML = `
|
|
202
|
+
<table><!-- ... --></table>
|
|
203
|
+
<div id="pager"></div>
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
const pagerContainer = this.querySelector('#pager')!;
|
|
207
|
+
this.pager = new Pager(pagerContainer, 100, 10); // 100 items, 10 per page
|
|
208
|
+
|
|
209
|
+
pagerContainer.addEventListener('pageselected', (e: PageSelectedEvent) => {
|
|
210
|
+
this.loadPage(e.detail);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async loadPage(page: number) {
|
|
215
|
+
const data = await fetchUsers(page);
|
|
216
|
+
this.renderer.render(data);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Updating Total Count
|
|
222
|
+
|
|
223
|
+
When the total number of items changes (e.g. after filtering):
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
this.pager.update(newTotalCount);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### API
|
|
230
|
+
|
|
231
|
+
| Method | Description |
|
|
232
|
+
|--------|-------------|
|
|
233
|
+
| `update(totalCount)` | Updates total count and re-renders page buttons |
|
|
234
|
+
| `getCurrentPage()` | Returns the current page number |
|
|
235
|
+
|
|
236
|
+
### Combined Example: TableRenderer + TableSorter + Pager
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { TableRenderer, TableSorter, Pager } from 'relaxjs/html';
|
|
240
|
+
|
|
241
|
+
class ProductList extends HTMLElement {
|
|
242
|
+
private renderer!: TableRenderer;
|
|
243
|
+
private sorter!: TableSorter;
|
|
244
|
+
private pager!: Pager;
|
|
245
|
+
|
|
246
|
+
connectedCallback() {
|
|
247
|
+
this.innerHTML = `
|
|
248
|
+
<table>
|
|
249
|
+
<thead>
|
|
250
|
+
<tr>
|
|
251
|
+
<th name="name">Name</th>
|
|
252
|
+
<th name="price">Price</th>
|
|
253
|
+
</tr>
|
|
254
|
+
</thead>
|
|
255
|
+
<tbody></tbody>
|
|
256
|
+
</table>
|
|
257
|
+
<template id="row-tpl">
|
|
258
|
+
<tr>
|
|
259
|
+
<td data-field="name"></td>
|
|
260
|
+
<td data-field="price"></td>
|
|
261
|
+
<td><button onclick="edit">Edit</button></td>
|
|
262
|
+
</tr>
|
|
263
|
+
</template>
|
|
264
|
+
<div id="pager"></div>
|
|
265
|
+
`;
|
|
266
|
+
|
|
267
|
+
const table = this.querySelector('table')!;
|
|
268
|
+
const template = this.querySelector('#row-tpl') as HTMLTemplateElement;
|
|
269
|
+
|
|
270
|
+
this.renderer = new TableRenderer(table, template, 'id', this);
|
|
271
|
+
this.sorter = new TableSorter(table, this);
|
|
272
|
+
this.pager = new Pager(this.querySelector('#pager')!, 0, 20);
|
|
273
|
+
|
|
274
|
+
this.addEventListener('sortchange', () => this.reload());
|
|
275
|
+
this.querySelector('#pager')!.addEventListener('pageselected', () => this.reload());
|
|
276
|
+
|
|
277
|
+
this.reload();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async reload() {
|
|
281
|
+
const page = this.pager.getCurrentPage();
|
|
282
|
+
const sort = this.sorter.getSortColumns();
|
|
283
|
+
const { items, total } = await fetchProducts(page, sort);
|
|
284
|
+
this.renderer.render(items);
|
|
285
|
+
this.pager.update(total);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
edit(data: any) {
|
|
289
|
+
console.log('Edit product:', data);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# html Template Engine
|
|
2
|
+
|
|
3
|
+
A lightweight HTML template engine with update capabilities. Creates templates that can be re-rendered with new data without recreating DOM nodes.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { html } from 'relaxjs/html';
|
|
9
|
+
|
|
10
|
+
// Create a template
|
|
11
|
+
const userCard = html`
|
|
12
|
+
<div class="user-card">
|
|
13
|
+
<h2>{{name}}</h2>
|
|
14
|
+
<p>{{email}}</p>
|
|
15
|
+
</div>
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
// Render with data
|
|
19
|
+
const result = userCard({ name: 'John', email: 'john@example.com' });
|
|
20
|
+
container.appendChild(result.fragment);
|
|
21
|
+
|
|
22
|
+
// Update with new data (no DOM recreation)
|
|
23
|
+
result.update({ name: 'Jane', email: 'jane@example.com' });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
### Mustache Bindings
|
|
29
|
+
|
|
30
|
+
Use `{{property}}` syntax to bind context properties to text content or attributes:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const template = html`
|
|
34
|
+
<a href="{{url}}" class="{{linkClass}}">{{linkText}}</a>
|
|
35
|
+
`;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Template Literal Substitutions
|
|
39
|
+
|
|
40
|
+
Use `${}` for static values or functions:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const staticClass = 'container';
|
|
44
|
+
const template = html`<div class="${staticClass}">{{content}}</div>`;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Event Handlers
|
|
48
|
+
|
|
49
|
+
Bind event handlers with context:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const row = html`
|
|
53
|
+
<tr>
|
|
54
|
+
<td>{{name}}</td>
|
|
55
|
+
<td>
|
|
56
|
+
<button onclick=${function() { this.onEdit(this.id); }}>Edit</button>
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const result = row({
|
|
62
|
+
id: 42,
|
|
63
|
+
name: 'Item',
|
|
64
|
+
onEdit(id) { console.log('Edit:', id); }
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Context Functions
|
|
69
|
+
|
|
70
|
+
Call methods from the context object:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const template = html`<div>{{formatPrice}}</div>`;
|
|
74
|
+
|
|
75
|
+
const result = template({
|
|
76
|
+
price: 99.99,
|
|
77
|
+
formatPrice() {
|
|
78
|
+
return `$${this.price.toFixed(2)}`;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Function Arguments
|
|
84
|
+
|
|
85
|
+
Pass arguments to context functions using the pipe syntax:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const template = html`<div>{{greet|name}}</div>`;
|
|
89
|
+
|
|
90
|
+
const result = template({
|
|
91
|
+
name: 'John',
|
|
92
|
+
greet(name) { return `Hello, ${name}!`; }
|
|
93
|
+
});
|
|
94
|
+
// Result: <div>Hello, John!</div>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The value after `|` is resolved from the context and passed to the function. Multiple arguments use comma separation:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const template = html`<div>{{format|name,title}}</div>`;
|
|
101
|
+
|
|
102
|
+
const result = template({
|
|
103
|
+
name: 'John',
|
|
104
|
+
title: 'Developer',
|
|
105
|
+
format(name, title) { return `${name} - ${title}`; }
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For value transformations using pipes (like `uppercase`, `currency`), use [compileTemplate](template.md) instead.
|
|
110
|
+
|
|
111
|
+
## API
|
|
112
|
+
|
|
113
|
+
### `html` (tagged template literal)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
function html(
|
|
117
|
+
templateStrings: TemplateStringsArray,
|
|
118
|
+
...substitutions: any[]
|
|
119
|
+
): (context: any) => RenderTemplate
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Creates a template function that accepts a context object and returns a `RenderTemplate`.
|
|
123
|
+
|
|
124
|
+
### `RenderTemplate`
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
interface RenderTemplate {
|
|
128
|
+
fragment: DocumentFragment;
|
|
129
|
+
update(context: any): void;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- `fragment`: The rendered DOM fragment. Add to the DOM once.
|
|
134
|
+
- `update(context)`: Re-renders with new data without recreating DOM nodes.
|
|
135
|
+
|
|
136
|
+
## Design
|
|
137
|
+
|
|
138
|
+
This template engine is designed for **single-use updateable templates**:
|
|
139
|
+
|
|
140
|
+
1. Create the template once
|
|
141
|
+
2. Render and add `fragment` to the DOM
|
|
142
|
+
3. Call `update()` to push changes to the existing nodes
|
|
143
|
+
|
|
144
|
+
For reusable templates that create multiple independent instances, use `compileTemplate` from [template](template.md).
|
|
145
|
+
|
|
146
|
+
## Property vs Attribute Binding
|
|
147
|
+
|
|
148
|
+
The engine automatically detects when to set element properties vs attributes:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Sets input.value property (not attribute)
|
|
152
|
+
const input = html`<input value="{{val}}">`;
|
|
153
|
+
|
|
154
|
+
// Sets data-id attribute
|
|
155
|
+
const div = html`<div data-id="{{id}}"></div>`;
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Custom Elements
|
|
159
|
+
|
|
160
|
+
Custom elements are automatically upgraded when encountered in templates.
|
|
161
|
+
|
|
162
|
+
## Limitations
|
|
163
|
+
|
|
164
|
+
The `html` template is optimized for simple, updateable templates. For advanced features, use [compileTemplate](template.md):
|
|
165
|
+
|
|
166
|
+
| Feature | `html` | `compileTemplate` |
|
|
167
|
+
|---------|--------|-------------------|
|
|
168
|
+
| Mustache bindings | ✅ | ✅ |
|
|
169
|
+
| Event handlers | ✅ | ❌ |
|
|
170
|
+
| In-place updates | ✅ | ✅ |
|
|
171
|
+
| Nested paths (`user.name`) | ❌ | ✅ |
|
|
172
|
+
| Loops (`loop="item in items"`) | ❌ | ✅ |
|
|
173
|
+
| Conditionals (`if`, `unless`) | ❌ | ✅ |
|
|
174
|
+
| Pipe transformations | ❌ | ✅ |
|
|
175
|
+
| Function calls with args | ✅ (via `\|`) | ✅ |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# HTML & Templating
|
|
2
|
+
|
|
3
|
+
This module provides templating utilities for rendering dynamic HTML content.
|
|
4
|
+
|
|
5
|
+
## Available Features
|
|
6
|
+
|
|
7
|
+
| Feature | Description | Use Case |
|
|
8
|
+
|---------|-------------|----------|
|
|
9
|
+
| [html](html.md) | Tagged template literal with update support | Single-use templates with in-place updates |
|
|
10
|
+
| [compileTemplate](template.md) | Full-featured template compiler | Reusable templates with loops, conditionals, pipes |
|
|
11
|
+
| [Pipes](../Pipes.md) | Value transformation functions | Format dates, currencies, text in templates |
|
|
12
|
+
| [TableRenderer](TableRenderer.md) | Table row renderer for Web Components | Data tables with row updates and button handlers |
|
|
13
|
+
|
|
14
|
+
## Quick Comparison
|
|
15
|
+
|
|
16
|
+
### html
|
|
17
|
+
|
|
18
|
+
Best for: Single templates that need efficient updates
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const card = html`<div>{{name}}</div>`;
|
|
22
|
+
const result = card({ name: 'John' });
|
|
23
|
+
container.appendChild(result.fragment);
|
|
24
|
+
result.update({ name: 'Jane' }); // Updates in place
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### compileTemplate
|
|
28
|
+
|
|
29
|
+
Best for: Complex templates with loops and conditionals
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const { content, render } = compileTemplate(`
|
|
33
|
+
<ul>
|
|
34
|
+
<li loop="item in items" if="item.visible">{{item.name}}</li>
|
|
35
|
+
</ul>
|
|
36
|
+
`);
|
|
37
|
+
render({ items: [...] });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### TableRenderer
|
|
41
|
+
|
|
42
|
+
Best for: Data tables in Web Components
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const renderer = new TableRenderer(table, template, 'id', this);
|
|
46
|
+
renderer.render(data);
|
|
47
|
+
renderer.updateRow(id, newData);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Choosing the Right Tool
|
|
51
|
+
|
|
52
|
+
- **Need in-place updates?** → Use `html`
|
|
53
|
+
- **Need loops/conditionals?** → Use `compileTemplate`
|
|
54
|
+
- **Building a data table?** → Use `TableRenderer`
|