@relax.js/core 1.0.3 → 1.0.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/README.md +194 -188
- package/dist/DependencyInjection.d.ts +42 -24
- package/dist/di/index.js +1 -1
- package/dist/di/index.js.map +3 -3
- package/dist/di/index.mjs +1 -1
- package/dist/di/index.mjs.map +3 -3
- package/dist/errors.d.ts +20 -0
- package/dist/forms/FormValidator.d.ts +1 -20
- package/dist/forms/ValidationRules.d.ts +2 -0
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +4 -4
- package/dist/forms/index.mjs +1 -1
- package/dist/forms/index.mjs.map +4 -4
- package/dist/html/TableRenderer.d.ts +1 -0
- package/dist/html/index.js.map +2 -2
- package/dist/html/index.mjs.map +2 -2
- package/dist/html/template.d.ts +4 -0
- package/dist/http/http.d.ts +1 -0
- package/dist/http/index.js.map +2 -2
- package/dist/http/index.mjs.map +2 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +3 -3
- package/dist/routing/index.js +3 -3
- package/dist/routing/index.js.map +3 -3
- package/dist/routing/index.mjs +3 -3
- package/dist/routing/index.mjs.map +3 -3
- package/dist/routing/routeTargetRegistry.d.ts +1 -0
- package/dist/routing/types.d.ts +2 -1
- package/dist/templates/NodeTemplate.d.ts +2 -0
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +2 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +2 -2
- package/docs/Architecture.md +333 -333
- package/docs/DependencyInjection.md +277 -237
- package/docs/Errors.md +87 -87
- package/docs/GettingStarted.md +231 -231
- package/docs/Pipes.md +5 -5
- package/docs/Translations.md +167 -312
- package/docs/WhyRelaxjs.md +336 -336
- package/docs/api/.nojekyll +1 -0
- package/docs/api/assets/hierarchy.js +1 -0
- package/docs/api/assets/highlight.css +120 -0
- package/docs/api/assets/icons.js +18 -0
- package/docs/api/assets/icons.svg +1 -0
- package/docs/api/assets/main.js +60 -0
- package/docs/api/assets/navigation.js +1 -0
- package/docs/api/assets/search.js +1 -0
- package/docs/api/assets/style.css +1633 -0
- package/docs/api/classes/http.WebSocketClient.html +26 -0
- package/docs/api/classes/i18n.LocaleChangeEvent.html +66 -0
- package/docs/api/classes/index.Blueprint.html +3 -0
- package/docs/api/classes/index.BoundNode.html +3 -0
- package/docs/api/classes/index.DigitsValidation.html +10 -0
- package/docs/api/classes/index.FormValidator.html +32 -0
- package/docs/api/classes/index.HttpError.html +13 -0
- package/docs/api/classes/index.LinkedList.html +26 -0
- package/docs/api/classes/index.NavigateRouteEvent.html +76 -0
- package/docs/api/classes/index.Node.html +15 -0
- package/docs/api/classes/index.PageSelectedEvent.html +61 -0
- package/docs/api/classes/index.Pager.html +4 -0
- package/docs/api/classes/index.RangeValidation.html +15 -0
- package/docs/api/classes/index.RelaxError.html +17 -0
- package/docs/api/classes/index.RequiredValidation.html +10 -0
- package/docs/api/classes/index.RouteError.html +11 -0
- package/docs/api/classes/index.RouteGuardError.html +12 -0
- package/docs/api/classes/index.RouteLink.html +779 -0
- package/docs/api/classes/index.RouteTarget.html +788 -0
- package/docs/api/classes/index.SSEClient.html +13 -0
- package/docs/api/classes/index.SSEDataEvent.html +63 -0
- package/docs/api/classes/index.ServiceCollection.html +28 -0
- package/docs/api/classes/index.ServiceContainer.html +24 -0
- package/docs/api/classes/index.SortChangeEvent.html +61 -0
- package/docs/api/classes/index.TableRenderer.html +5 -0
- package/docs/api/classes/index.TableSorter.html +4 -0
- package/docs/api/enums/index.GuardResult.html +9 -0
- package/docs/api/functions/elements.formError.html +6 -0
- package/docs/api/functions/elements.selectOne.html +6 -0
- package/docs/api/functions/i18n.getCurrentLocale.html +3 -0
- package/docs/api/functions/i18n.loadNamespace.html +7 -0
- package/docs/api/functions/i18n.loadNamespaces.html +6 -0
- package/docs/api/functions/i18n.onMissingTranslation.html +7 -0
- package/docs/api/functions/i18n.setLocale.html +7 -0
- package/docs/api/functions/i18n.setMessageFormatter.html +7 -0
- package/docs/api/functions/i18n.t.html +9 -0
- package/docs/api/functions/index.BooleanConverter.html +6 -0
- package/docs/api/functions/index.ContainerService.html +13 -0
- package/docs/api/functions/index.DateConverter.html +11 -0
- package/docs/api/functions/index.Inject.html +16 -0
- package/docs/api/functions/index.NumberConverter.html +5 -0
- package/docs/api/functions/index.RegisterValidator.html +7 -0
- package/docs/api/functions/index.applyPipes.html +17 -0
- package/docs/api/functions/index.asyncHandler.html +11 -0
- package/docs/api/functions/index.capitalizePipe.html +4 -0
- package/docs/api/functions/index.clearPendingNavigations.html +1 -0
- package/docs/api/functions/index.compileTemplate.html +26 -0
- package/docs/api/functions/index.configure.html +5 -0
- package/docs/api/functions/index.createBluePrint.html +1 -0
- package/docs/api/functions/index.createConverterFromDataType.html +4 -0
- package/docs/api/functions/index.createConverterFromInputType.html +5 -0
- package/docs/api/functions/index.createPipeRegistry.html +12 -0
- package/docs/api/functions/index.currencyPipe.html +9 -0
- package/docs/api/functions/index.datePipe.html +9 -0
- package/docs/api/functions/index.daysAgoPipe.html +8 -0
- package/docs/api/functions/index.defaultPipe.html +5 -0
- package/docs/api/functions/index.defineRoutes.html +8 -0
- package/docs/api/functions/index.del.html +8 -0
- package/docs/api/functions/index.findRouteByName.html +5 -0
- package/docs/api/functions/index.findRouteByUrl.html +4 -0
- package/docs/api/functions/index.firstPipe.html +4 -0
- package/docs/api/functions/index.generateSequentialId.html +21 -0
- package/docs/api/functions/index.get.html +9 -0
- package/docs/api/functions/index.getDataConverter.html +11 -0
- package/docs/api/functions/index.getParentComponent.html +18 -0
- package/docs/api/functions/index.getValidator.html +4 -0
- package/docs/api/functions/index.html.html +19 -0
- package/docs/api/functions/index.joinPipe.html +5 -0
- package/docs/api/functions/index.keysPipe.html +4 -0
- package/docs/api/functions/index.lastPipe.html +4 -0
- package/docs/api/functions/index.lowercasePipe.html +4 -0
- package/docs/api/functions/index.mapFormToClass.html +17 -0
- package/docs/api/functions/index.matchRoute.html +5 -0
- package/docs/api/functions/index.navigate.html +8 -0
- package/docs/api/functions/index.onError.html +8 -0
- package/docs/api/functions/index.piecesPipe.html +8 -0
- package/docs/api/functions/index.post.html +9 -0
- package/docs/api/functions/index.printRoutes.html +2 -0
- package/docs/api/functions/index.put.html +9 -0
- package/docs/api/functions/index.readData.html +17 -0
- package/docs/api/functions/index.registerRouteTarget.html +9 -0
- package/docs/api/functions/index.reportError.html +10 -0
- package/docs/api/functions/index.request.html +8 -0
- package/docs/api/functions/index.resolveValue.html +18 -0
- package/docs/api/functions/index.setFetch.html +6 -0
- package/docs/api/functions/index.setFormData.html +17 -0
- package/docs/api/functions/index.shortenPipe.html +5 -0
- package/docs/api/functions/index.startRouting.html +6 -0
- package/docs/api/functions/index.ternaryPipe.html +6 -0
- package/docs/api/functions/index.trimPipe.html +4 -0
- package/docs/api/functions/index.unregisterRouteTarget.html +3 -0
- package/docs/api/functions/index.uppercasePipe.html +4 -0
- package/docs/api/hierarchy.html +1 -0
- package/docs/api/index.html +323 -0
- package/docs/api/interfaces/http.SimpleDataEvent.html +3 -0
- package/docs/api/interfaces/http.WebSocketAbstraction.html +9 -0
- package/docs/api/interfaces/http.WebSocketCodec.html +4 -0
- package/docs/api/interfaces/http.WebSocketOptions.html +20 -0
- package/docs/api/interfaces/index.CompiledTemplate.html +10 -0
- package/docs/api/interfaces/index.DataLoader.html +19 -0
- package/docs/api/interfaces/index.EngineConfig.html +11 -0
- package/docs/api/interfaces/index.ErrorContext.html +4 -0
- package/docs/api/interfaces/index.FormReaderOptions.html +8 -0
- package/docs/api/interfaces/index.HttpOptions.html +16 -0
- package/docs/api/interfaces/index.HttpResponse.html +17 -0
- package/docs/api/interfaces/index.LoadRoute.html +7 -0
- package/docs/api/interfaces/index.NavigateOptions.html +7 -0
- package/docs/api/interfaces/index.PipeRegistry.html +12 -0
- package/docs/api/interfaces/index.RegistrationOptions.html +22 -0
- package/docs/api/interfaces/index.RenderTemplate.html +7 -0
- package/docs/api/interfaces/index.RequestOptions.html +11 -0
- package/docs/api/interfaces/index.Routable.html +10 -0
- package/docs/api/interfaces/index.Route.html +13 -0
- package/docs/api/interfaces/index.RouteGuard.html +2 -0
- package/docs/api/interfaces/index.RouteValue.html +6 -0
- package/docs/api/interfaces/index.SSEOptions.html +24 -0
- package/docs/api/interfaces/index.ValidationContext.html +8 -0
- package/docs/api/interfaces/index.ValidatorOptions.html +14 -0
- package/docs/api/media/Architecture.md +333 -0
- package/docs/api/media/DependencyInjection.md +277 -0
- package/docs/api/media/GettingStarted.md +231 -0
- package/docs/api/media/HttpClient.md +459 -0
- package/docs/api/media/Pipes.md +211 -0
- package/docs/api/media/Routing.md +332 -0
- package/docs/api/media/WhyRelaxjs.md +336 -0
- package/docs/api/media/forms.md +99 -0
- package/docs/api/media/html.md +175 -0
- package/docs/api/media/i18n.md +354 -0
- package/docs/api/media/utilities.md +143 -0
- package/docs/api/media/validation.md +351 -0
- package/docs/api/modules/collections_Index.html +1 -0
- package/docs/api/modules/di.html +1 -0
- package/docs/api/modules/elements.html +1 -0
- package/docs/api/modules/forms.html +1 -0
- package/docs/api/modules/html.html +1 -0
- package/docs/api/modules/http.html +1 -0
- package/docs/api/modules/i18n.html +1 -0
- package/docs/api/modules/index.html +1 -0
- package/docs/api/modules/routing.html +1 -0
- package/docs/api/modules/utils.html +1 -0
- package/docs/api/modules.html +1 -0
- package/docs/api/types/http.WebSocketFactory.html +2 -0
- package/docs/api/types/i18n.MessageFormatter.html +3 -0
- package/docs/api/types/i18n.MissingTranslationHandler.html +1 -0
- package/docs/api/types/index.Constructor.html +7 -0
- package/docs/api/types/index.ConverterFunc.html +2 -0
- package/docs/api/types/index.DataType.html +2 -0
- package/docs/api/types/index.InputType.html +2 -0
- package/docs/api/types/index.PipeFunction.html +6 -0
- package/docs/api/types/index.RouteData.html +1 -0
- package/docs/api/types/index.RouteMatchResult.html +9 -0
- package/docs/api/types/index.RouteParamType.html +1 -0
- package/docs/api/types/index.RouteSegmentType.html +2 -0
- package/docs/api/types/index.SSEEventFactory.html +5 -0
- package/docs/api/types/index.ServiceScope.html +10 -0
- package/docs/api/types/index.SortColumn.html +3 -0
- package/docs/api/variables/i18n.formatICU.html +3 -0
- package/docs/api/variables/index.container.html +6 -0
- package/docs/api/variables/index.defaultPipes.html +6 -0
- package/docs/api/variables/index.internalRoutes.html +1 -0
- package/docs/api/variables/index.serviceCollection.html +6 -0
- package/docs/api.json +93171 -0
- package/docs/elements/dom.md +102 -102
- package/docs/forms/creating-form-components.md +924 -924
- package/docs/forms/form-api.md +94 -94
- package/docs/forms/forms.md +99 -99
- package/docs/forms/patterns.md +311 -311
- package/docs/forms/reading-writing.md +365 -365
- package/docs/forms/validation.md +351 -351
- package/docs/html/TableRenderer.md +291 -291
- package/docs/html/html.md +175 -175
- package/docs/html/index.md +54 -54
- package/docs/html/template.md +422 -422
- package/docs/http/HttpClient.md +459 -459
- package/docs/http/ServerSentEvents.md +184 -184
- package/docs/http/index.md +109 -109
- package/docs/i18n/i18n.md +49 -4
- package/docs/i18n/intl-standard.md +178 -178
- package/docs/routing/RouteLink.md +98 -98
- package/docs/routing/Routing.md +332 -332
- package/docs/routing/layouts.md +207 -207
- package/docs/utilities.md +143 -143
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,188 +1,194 @@
|
|
|
1
|
-
# Relaxjs
|
|
2
|
-
|
|
3
|
-
**Ship faster with less code.**
|
|
4
|
-
|
|
5
|
-
Web Component library with routing, forms, DI, templating, and i18n. No virtual DOM, no build magic, no surprise re-renders.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
##
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
|
116
|
-
|
|
117
|
-
| **
|
|
118
|
-
| **
|
|
119
|
-
| **
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- **
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
|
150
|
-
|
|
151
|
-
| **
|
|
152
|
-
| **
|
|
153
|
-
| **
|
|
154
|
-
| **
|
|
155
|
-
| **
|
|
156
|
-
| **
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
- [
|
|
177
|
-
- [
|
|
178
|
-
- [
|
|
179
|
-
- [
|
|
180
|
-
- [
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
1
|
+
# Relaxjs
|
|
2
|
+
|
|
3
|
+
**Ship faster with less code.**
|
|
4
|
+
|
|
5
|
+
Web Component library with routing, forms, DI, templating, and i18n. No virtual DOM, no build magic, no surprise re-renders.
|
|
6
|
+
|
|
7
|
+
- ~20KB gzipped, one dependency
|
|
8
|
+
- Native Web Components, zero vendor lock-in
|
|
9
|
+
- Use only what you need: forms, routing, DI, i18n are all independent
|
|
10
|
+
- No build step required, no compiler, no CLI
|
|
11
|
+
- Standard HTML, standard DOM, standard async/await
|
|
12
|
+
|
|
13
|
+
## Why Relaxjs?
|
|
14
|
+
|
|
15
|
+
Modern frameworks solve problems you might not have. Relaxjs takes the opposite approach:
|
|
16
|
+
|
|
17
|
+
| Framework Approach | Relaxjs Approach |
|
|
18
|
+
|-------------------|------------------|
|
|
19
|
+
| Virtual DOM diffing | Direct DOM manipulation |
|
|
20
|
+
| Reactive state management | Explicit updates |
|
|
21
|
+
| Custom template syntax | Standard HTML |
|
|
22
|
+
| Framework-specific lifecycle | Native Web Component lifecycle |
|
|
23
|
+
| Magic re-renders | You control what updates |
|
|
24
|
+
| Custom rendering pipeline | Native async/await everywhere |
|
|
25
|
+
|
|
26
|
+
> [Read the detailed comparison](docs/WhyRelaxjs.md)
|
|
27
|
+
|
|
28
|
+
**The result:** You always know *when* something ran, *why* it ran, and *what* triggered it.
|
|
29
|
+
|
|
30
|
+
## What Relaxjs Adds
|
|
31
|
+
|
|
32
|
+
Web Components give you encapsulation and lifecycle hooks. Relaxjs fills the gaps:
|
|
33
|
+
|
|
34
|
+
| Vanilla Web Components | With Relaxjs |
|
|
35
|
+
|------------------------|--------------|
|
|
36
|
+
| Manual form serialization | `readData(form)` returns typed objects (send it directly to backend) |
|
|
37
|
+
| Query string parsing | Named routes with typed parameters |
|
|
38
|
+
| DIY validation logic | `FormValidator` with HTML5 integration |
|
|
39
|
+
| No component library | Table, Tabs, TreeView, Menu ready to use |
|
|
40
|
+
| Manual service wiring | Decorator-based dependency injection |
|
|
41
|
+
| Raw fetch boilerplate | Simple HTTP client for backend calls |
|
|
42
|
+
|
|
43
|
+
You write less boilerplate while keeping full control.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @relax.js/core
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Examples
|
|
52
|
+
|
|
53
|
+
### Form Handling
|
|
54
|
+
|
|
55
|
+
Read and write form data with automatic type conversion:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { setFormData, readData } from '@relax.js/core';
|
|
59
|
+
|
|
60
|
+
// Populate a form from an object
|
|
61
|
+
const user = { name: 'John', email: 'john@example.com', age: 30 };
|
|
62
|
+
setFormData(form, user);
|
|
63
|
+
|
|
64
|
+
// Read form data back (with types!)
|
|
65
|
+
const data = readData(form);
|
|
66
|
+
// { name: 'John', email: 'john@example.com', age: 30 }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Supports nested objects (`user.address.city`), arrays (`tags[]`), and automatic type conversion for numbers, booleans, and dates.
|
|
70
|
+
|
|
71
|
+
> [Form utilities docs](docs/forms/forms.md)
|
|
72
|
+
|
|
73
|
+
### Client-Side Routing
|
|
74
|
+
|
|
75
|
+
Define routes and let the router handle navigation:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { defineRoutes, navigate, startRouting } from '@relax.js/core';
|
|
79
|
+
|
|
80
|
+
defineRoutes([
|
|
81
|
+
{ name: 'home', path: '/', componentTagName: 'app-home' },
|
|
82
|
+
{ name: 'user', path: '/users/:id', componentTagName: 'app-user' },
|
|
83
|
+
{ name: 'settings', path: '/settings', componentTagName: 'app-settings' }
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
startRouting();
|
|
87
|
+
|
|
88
|
+
// Navigate programmatically
|
|
89
|
+
navigate('user', { params: { id: '123' } });
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<r-route-target></r-route-target>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> [Routing docs](docs/routing/Routing.md)
|
|
97
|
+
|
|
98
|
+
### Form Validation
|
|
99
|
+
|
|
100
|
+
HTML5-style validation with custom rules and error summaries:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { FormValidator } from '@relax.js/core';
|
|
104
|
+
|
|
105
|
+
const validator = new FormValidator(form, {
|
|
106
|
+
useSummary: true,
|
|
107
|
+
submitCallback: () => saveData()
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> [Validation docs](docs/forms/validation.md)
|
|
112
|
+
|
|
113
|
+
## What's Included
|
|
114
|
+
|
|
115
|
+
| Feature | Description |
|
|
116
|
+
|---------|-------------|
|
|
117
|
+
| **Form Utilities** | Read/write forms, type conversion, validation |
|
|
118
|
+
| **Routing** | Named routes, typed parameters, guards, layouts, multiple targets |
|
|
119
|
+
| **HTML Templates** | `html` tagged templates with data binding and in-place updates |
|
|
120
|
+
| **HTTP Client** | Type-safe `get`/`post`/`put`/`del` with automatic JWT |
|
|
121
|
+
| **WebSocket** | Auto-reconnect, message queuing, typed messages |
|
|
122
|
+
| **SSE** | Server-Sent Events dispatched as DOM events |
|
|
123
|
+
| **Dependency Injection** | Decorator-based DI with constructor and property injection |
|
|
124
|
+
| **i18n** | ICU message format, pluralization, locale-aware formatting |
|
|
125
|
+
| **Pipes** | 15 built-in data transformations for templates |
|
|
126
|
+
|
|
127
|
+
## Where Relaxjs Fits
|
|
128
|
+
|
|
129
|
+
Relaxjs is a good choice when:
|
|
130
|
+
|
|
131
|
+
- You're building a **small-to-medium SPA** where you want direct control over the DOM
|
|
132
|
+
- Your team prefers **vanilla Web Components** over framework abstractions
|
|
133
|
+
- You want **gradual adoption** - use only the parts you need, no all-or-nothing buy-in
|
|
134
|
+
- **Bundle size and simplicity** matter more than ecosystem breadth
|
|
135
|
+
- You want to **understand what your code does** - no hidden re-renders, no magic proxies, no compiler transforms
|
|
136
|
+
|
|
137
|
+
## Where Relaxjs Doesn't Fit
|
|
138
|
+
|
|
139
|
+
Relaxjs is not the right tool for everything:
|
|
140
|
+
|
|
141
|
+
- **Large-scale apps with complex state** - Relaxjs has no reactive state management, no global store, no computed properties. If your UI has dozens of interdependent data flows, you'll be writing a lot of manual update logic.
|
|
142
|
+
- **Server-side rendering / static site generation** - Relaxjs is client-only. If you need SEO, fast first-paint from the server, or pre-rendered pages, look at Next.js, Nuxt, or SvelteKit.
|
|
143
|
+
- **Big teams that need a large talent pool** - React and Angular developers are everywhere. Finding developers who know Relaxjs (or are willing to learn a small library) is harder.
|
|
144
|
+
- **Rich ecosystem needs** - There's no component marketplace, no DevTools extension, no community middleware. You build what you need or use vanilla JS libraries.
|
|
145
|
+
- **Mobile / native targets** - No React Native equivalent, no Ionic integration. Relaxjs is for the browser.
|
|
146
|
+
|
|
147
|
+
## How It Compares
|
|
148
|
+
|
|
149
|
+
| | Relaxjs | React | Angular | Vue | Svelte |
|
|
150
|
+
|---|---|---|---|---|---|
|
|
151
|
+
| **Approach** | Web Components | Virtual DOM | Full framework | Virtual DOM | Compiler |
|
|
152
|
+
| **Bundle size** | ~20KB gzipped | ~45KB | ~150KB+ | ~33KB | ~2KB runtime |
|
|
153
|
+
| **Learning curve** | Low (vanilla TS) | Medium | High | Medium | Low-Medium |
|
|
154
|
+
| **State management** | Explicit DOM updates | Hooks / Redux / Zustand | RxJS / Signals | Reactive refs | Stores / runes |
|
|
155
|
+
| **Routing** | Built-in (simple) | react-router (separate) | Built-in (full) | vue-router (separate) | SvelteKit |
|
|
156
|
+
| **Forms** | Built-in (HTML5 native) | Controlled / uncontrolled | Reactive forms | v-model | bind: |
|
|
157
|
+
| **SSR** | No | Yes | Yes | Yes | Yes |
|
|
158
|
+
| **Ecosystem** | Small | Massive | Large | Large | Growing |
|
|
159
|
+
| **DI** | Built-in | None (Context API) | Built-in | Provide / Inject | None |
|
|
160
|
+
| **i18n** | Built-in (ICU) | i18next etc. | Built-in | vue-i18n | i18next etc. |
|
|
161
|
+
| **DevTools** | Browser DevTools | React DevTools | Angular DevTools | Vue DevTools | Svelte DevTools |
|
|
162
|
+
| **Community size** | Small | Very large | Large | Large | Medium |
|
|
163
|
+
|
|
164
|
+
## Philosophy
|
|
165
|
+
|
|
166
|
+
This isn't a framework - it's a library. Use what you need:
|
|
167
|
+
|
|
168
|
+
- Need just form handling? Import `setFormData` and `readData`.
|
|
169
|
+
- Need routing? Add `defineRoutes` and `r-route-target`.
|
|
170
|
+
- Need everything? It's all there.
|
|
171
|
+
|
|
172
|
+
No buy-in required. No migration path to worry about.
|
|
173
|
+
|
|
174
|
+
## Documentation
|
|
175
|
+
|
|
176
|
+
- [Why Relaxjs?](docs/WhyRelaxjs.md) - Detailed comparison with frameworks
|
|
177
|
+
- [Getting Started](docs/GettingStarted.md) - Progressive adoption guide (7 levels)
|
|
178
|
+
- [Architecture](docs/Architecture.md)
|
|
179
|
+
- [Form Utilities](docs/forms/forms.md) - Validation, reading/writing, custom form components
|
|
180
|
+
- [Routing](docs/routing/Routing.md) - Routes, guards, layouts, navigation
|
|
181
|
+
- [HTML Templates](docs/html/html.md) - Tagged templates with data binding
|
|
182
|
+
- [HTTP & WebSocket](docs/http/HttpClient.md) - REST calls, WebSocket, SSE
|
|
183
|
+
- [Dependency Injection](docs/DependencyInjection.md)
|
|
184
|
+
- [i18n](docs/i18n/i18n.md) - Translations, ICU format, locale switching
|
|
185
|
+
- [Pipes](docs/Pipes.md) - Data transformations for templates
|
|
186
|
+
- [Utilities](docs/utilities.md) - Sequential IDs, LinkedList, helpers
|
|
187
|
+
|
|
188
|
+
## Browser Support
|
|
189
|
+
|
|
190
|
+
Works in all browsers that support Web Components (Chrome, Firefox, Safari, Edge).
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT
|
|
@@ -65,42 +65,60 @@ export interface RegistrationOptions {
|
|
|
65
65
|
properties?: Record<string, string | Constructor>;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Field decorator that
|
|
69
|
-
*
|
|
68
|
+
* Field decorator that injects a service from the global DI container.
|
|
69
|
+
* The service is resolved when the class instance is created (not at class definition time),
|
|
70
|
+
* so services must be registered before the first instance is created.
|
|
70
71
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* logger: Logger, // Inject by type
|
|
76
|
-
* audit: 'auditLogger' // Inject by key
|
|
77
|
-
* }
|
|
78
|
-
* })
|
|
79
|
-
* class UserService {
|
|
80
|
-
* @Inject(Logger)
|
|
81
|
-
* private logger!: Logger;
|
|
72
|
+
* Works with web components regardless of how they are created:
|
|
73
|
+
* - By the browser (HTML parsing): services are resolved during construction
|
|
74
|
+
* - By application code (`document.createElement` or `new`): same behavior
|
|
75
|
+
* - Injected fields are available in `connectedCallback` and all lifecycle methods
|
|
82
76
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Using `@Inject` in a web component
|
|
79
|
+
* class UserPanel extends HTMLElement {
|
|
80
|
+
* @Inject(UserService)
|
|
81
|
+
* private userService!: UserService;
|
|
85
82
|
*
|
|
86
|
-
*
|
|
83
|
+
* connectedCallback() {
|
|
84
|
+
* // userService is already resolved and ready to use
|
|
85
|
+
* const user = this.userService.getCurrentUser();
|
|
86
|
+
* this.render(user);
|
|
87
|
+
* }
|
|
87
88
|
* }
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* // Services must be registered before components are created.
|
|
92
|
+
* // In your app entry point (e.g. main.ts):
|
|
93
|
+
* serviceCollection.registerByType(UserService, { inject: [ApiClient] });
|
|
94
|
+
* serviceCollection.registerByType(ApiClient, { inject: [] });
|
|
95
|
+
*
|
|
96
|
+
* // Now components can be created (by browser or code)
|
|
97
|
+
* customElements.define('user-panel', UserPanel);
|
|
88
98
|
*/
|
|
89
99
|
export declare function Inject<T extends object>(typeOrKey: Constructor<T> | string): (_: undefined, context: ClassFieldDecoratorContext) => (this: any) => T;
|
|
90
100
|
/**
|
|
91
|
-
* Class decorator that
|
|
92
|
-
*
|
|
101
|
+
* Class decorator that registers a service in the global DI container.
|
|
102
|
+
* Registration happens at class definition time (when the module loads),
|
|
103
|
+
* so import the module before creating instances that depend on this service.
|
|
93
104
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
105
|
+
* For web components: use `@ContainerService` on services, not on the
|
|
106
|
+
* components themselves. Components use `@Inject` to consume services.
|
|
96
107
|
*
|
|
97
108
|
* @param options - Registration configuration including scope and dependencies
|
|
98
109
|
*
|
|
99
110
|
* @example
|
|
100
|
-
* //
|
|
101
|
-
* @ContainerService({ inject: [
|
|
102
|
-
* class
|
|
103
|
-
* constructor(private
|
|
111
|
+
* // Register a service that components can inject
|
|
112
|
+
* @ContainerService({ inject: [ApiClient] })
|
|
113
|
+
* class UserService {
|
|
114
|
+
* constructor(private api: ApiClient) {}
|
|
115
|
+
* getCurrentUser() { return this.api.get('/user'); }
|
|
116
|
+
* }
|
|
117
|
+
*
|
|
118
|
+
* // Component consumes the service
|
|
119
|
+
* class UserPanel extends HTMLElement {
|
|
120
|
+
* @Inject(UserService)
|
|
121
|
+
* private userService!: UserService;
|
|
104
122
|
* }
|
|
105
123
|
*
|
|
106
124
|
* @example
|
package/dist/di/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var d=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var x=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},C=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of f(t))!h.call(n,s)&&s!==e&&d(n,s,{get:()=>t[s],enumerable:!(r=y(t,s))||r.enumerable});return n};var T=n=>C(d({},"__esModule",{value:!0}),n);var b={};x(b,{ContainerService:()=>
|
|
1
|
+
var d=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var x=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},C=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of f(t))!h.call(n,s)&&s!==e&&d(n,s,{get:()=>t[s],enumerable:!(r=y(t,s))||r.enumerable});return n};var T=n=>C(d({},"__esModule",{value:!0}),n);var b={};x(b,{ContainerService:()=>j,Inject:()=>m,ServiceCollection:()=>a,ServiceContainer:()=>l,container:()=>v,serviceCollection:()=>g});module.exports=T(b);var u=class extends Error{constructor(e,r){super(e);this.context=r}},p=null;function o(n,t){let e=new u(n,t);if(p){let r=!1;if(p(e,{suppress(){r=!0}}),r)return null}return e}function m(n){return(t,e)=>function(){return v.resolve(n)}}function j(n){return t=>{let e=n??{inject:[]};e.key?g.register(t,e):g.registerByType(t,e)}}var c=class{constructor(t,e,r,s={},i,w){this.classConstructor=t;this.scope=e;this.inject=r;this.properties=s;this.key=i;this.instance=w}},a=class{constructor(){this.servicesByKey=new Map;this.servicesByClassName=new Map}register(t,e){this.validateRegistration(t,e);let r=new c(t,e.scope??"global",e.inject,e.properties??{},e.key,e.instance);e.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}registerByType(t,e){this.checkNameCollision(t),e&&this.validateRegistration(t,e);let r=new c(t,e?.scope,e?.inject??[],e?.properties,e?.key,e?.instance);e?.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}checkNameCollision(t){let e=this.servicesByClassName.get(t.name);if(e&&e.classConstructor!==t){let r=o("Service name collision: different class registered with same name",{service:t.name});if(r)throw r}}validateRegistration(t,e){if(this.checkNameCollision(t),e.key){let r=this.servicesByKey.get(e.key);if(r&&r.classConstructor!==t){let s=o("Service key already registered to a different class",{key:e.key,existingClass:r.classConstructor.name,newClass:t.name});if(s)throw s}}if(e.instance&&e.inject.length>0){let r=o("Service has both instance and inject (inject will be ignored)",{service:t.name});if(r)throw r}}tryGet(t){return typeof t=="string"?this.servicesByKey.get(t):this.servicesByClassName.get(t.name)}get(t){let e=this.tryGet(t);if(!e){let r=typeof t=="string"?t:t.name,s=o(`Failed to resolve service '${r}'`,{service:r,registeredTypes:Array.from(this.servicesByClassName.keys()),registeredKeys:Array.from(this.servicesByKey.keys())});if(s)throw s}return e}};var l=class{constructor(t){this.serviceCollection=t;this.instances=new Map}resolve(t){let e=typeof t=="string"?t:t.name;if(this.instances.has(e))return this.instances.get(e);let r=this.serviceCollection.get(t);if(!r){let i=o(`Failed to resolve service '${e}'`,{service:e});if(i)throw i;return}if(r.instance){let i=r.instance;return this.injectFields(i,r),this.instances.set(e,i),i}let s=this.createInstance(r);return r.scope==="global"&&this.instances.set(e,s),this.injectFields(s,r),s}createInstance(t){let e=t.classConstructor,r=t.inject.map(s=>this.resolve(s));return new e(...r)}injectFields(t,e){for(let[r,s]of Object.entries(e.properties))t[r]=this.resolve(s)}},g=new a,v=new l(g);
|
|
2
2
|
//# sourceMappingURL=index.js.map
|