@relax.js/core 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DependencyInjection.d.ts +3 -3
- package/dist/collections/LinkedList.d.ts +9 -8
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +3 -3
- package/dist/collections/index.mjs +1 -1
- package/dist/collections/index.mjs.map +3 -3
- package/dist/di/index.js +1 -1
- package/dist/di/index.js.map +2 -2
- package/dist/di/index.mjs +1 -1
- package/dist/di/index.mjs.map +2 -2
- package/dist/elements/index.js +1 -1
- package/dist/elements/index.js.map +1 -1
- package/dist/forms/FormValidator.d.ts +2 -2
- package/dist/forms/ValidationRules.d.ts +2 -6
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +3 -3
- package/dist/forms/index.mjs +1 -1
- package/dist/forms/index.mjs.map +3 -3
- package/dist/forms/setFormData.d.ts +52 -1
- package/dist/html/index.js +1 -1
- package/dist/html/index.js.map +3 -3
- package/dist/html/index.mjs +1 -1
- package/dist/html/index.mjs.map +3 -3
- package/dist/http/ServerSentEvents.d.ts +1 -1
- package/dist/http/SimpleWebSocket.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/index.js.map +3 -3
- package/dist/http/index.mjs +1 -1
- package/dist/http/index.mjs.map +3 -3
- package/dist/i18n/icu.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/index.js.map +2 -2
- package/dist/i18n/index.mjs +1 -1
- package/dist/i18n/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/NavigateRouteEvent.d.ts +4 -4
- package/dist/routing/index.js +2 -2
- 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/navigation.d.ts +1 -1
- package/dist/templates/NodeTemplate.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +3 -3
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +3 -3
- package/docs/GettingStarted.md +7 -0
- package/docs/api.json +34 -12
- package/docs/forms/reading-writing.md +137 -1
- package/docs/setup/bootstrapping.md +154 -0
- package/docs/setup/build-and-deploy.md +183 -0
- package/docs/setup/project-structure.md +170 -0
- package/docs/setup/vite.md +175 -0
- package/package.json +3 -2
- package/docs/api/.nojekyll +0 -1
- package/docs/api/assets/hierarchy.js +0 -1
- package/docs/api/assets/highlight.css +0 -120
- package/docs/api/assets/icons.js +0 -18
- package/docs/api/assets/icons.svg +0 -1
- package/docs/api/assets/main.js +0 -60
- package/docs/api/assets/navigation.js +0 -1
- package/docs/api/assets/search.js +0 -1
- package/docs/api/assets/style.css +0 -1633
- package/docs/api/classes/http.WebSocketClient.html +0 -26
- package/docs/api/classes/i18n.LocaleChangeEvent.html +0 -66
- package/docs/api/classes/index.Blueprint.html +0 -3
- package/docs/api/classes/index.BoundNode.html +0 -3
- package/docs/api/classes/index.DigitsValidation.html +0 -10
- package/docs/api/classes/index.FormValidator.html +0 -32
- package/docs/api/classes/index.HttpError.html +0 -13
- package/docs/api/classes/index.LinkedList.html +0 -26
- package/docs/api/classes/index.NavigateRouteEvent.html +0 -76
- package/docs/api/classes/index.Node.html +0 -15
- package/docs/api/classes/index.PageSelectedEvent.html +0 -61
- package/docs/api/classes/index.Pager.html +0 -4
- package/docs/api/classes/index.RangeValidation.html +0 -15
- package/docs/api/classes/index.RelaxError.html +0 -17
- package/docs/api/classes/index.RequiredValidation.html +0 -10
- package/docs/api/classes/index.RouteError.html +0 -11
- package/docs/api/classes/index.RouteGuardError.html +0 -12
- package/docs/api/classes/index.RouteLink.html +0 -779
- package/docs/api/classes/index.RouteTarget.html +0 -788
- package/docs/api/classes/index.SSEClient.html +0 -13
- package/docs/api/classes/index.SSEDataEvent.html +0 -63
- package/docs/api/classes/index.ServiceCollection.html +0 -28
- package/docs/api/classes/index.ServiceContainer.html +0 -24
- package/docs/api/classes/index.SortChangeEvent.html +0 -61
- package/docs/api/classes/index.TableRenderer.html +0 -5
- package/docs/api/classes/index.TableSorter.html +0 -4
- package/docs/api/enums/index.GuardResult.html +0 -9
- package/docs/api/functions/elements.formError.html +0 -6
- package/docs/api/functions/elements.selectOne.html +0 -6
- package/docs/api/functions/i18n.getCurrentLocale.html +0 -3
- package/docs/api/functions/i18n.loadNamespace.html +0 -7
- package/docs/api/functions/i18n.loadNamespaces.html +0 -6
- package/docs/api/functions/i18n.onMissingTranslation.html +0 -7
- package/docs/api/functions/i18n.setLocale.html +0 -7
- package/docs/api/functions/i18n.setMessageFormatter.html +0 -7
- package/docs/api/functions/i18n.t.html +0 -9
- package/docs/api/functions/index.BooleanConverter.html +0 -6
- package/docs/api/functions/index.ContainerService.html +0 -13
- package/docs/api/functions/index.DateConverter.html +0 -11
- package/docs/api/functions/index.Inject.html +0 -16
- package/docs/api/functions/index.NumberConverter.html +0 -5
- package/docs/api/functions/index.RegisterValidator.html +0 -7
- package/docs/api/functions/index.applyPipes.html +0 -17
- package/docs/api/functions/index.asyncHandler.html +0 -11
- package/docs/api/functions/index.capitalizePipe.html +0 -4
- package/docs/api/functions/index.clearPendingNavigations.html +0 -1
- package/docs/api/functions/index.compileTemplate.html +0 -26
- package/docs/api/functions/index.configure.html +0 -5
- package/docs/api/functions/index.createBluePrint.html +0 -1
- package/docs/api/functions/index.createConverterFromDataType.html +0 -4
- package/docs/api/functions/index.createConverterFromInputType.html +0 -5
- package/docs/api/functions/index.createPipeRegistry.html +0 -12
- package/docs/api/functions/index.currencyPipe.html +0 -9
- package/docs/api/functions/index.datePipe.html +0 -9
- package/docs/api/functions/index.daysAgoPipe.html +0 -8
- package/docs/api/functions/index.defaultPipe.html +0 -5
- package/docs/api/functions/index.defineRoutes.html +0 -8
- package/docs/api/functions/index.del.html +0 -8
- package/docs/api/functions/index.findRouteByName.html +0 -5
- package/docs/api/functions/index.findRouteByUrl.html +0 -4
- package/docs/api/functions/index.firstPipe.html +0 -4
- package/docs/api/functions/index.generateSequentialId.html +0 -21
- package/docs/api/functions/index.get.html +0 -9
- package/docs/api/functions/index.getDataConverter.html +0 -11
- package/docs/api/functions/index.getParentComponent.html +0 -18
- package/docs/api/functions/index.getValidator.html +0 -4
- package/docs/api/functions/index.html.html +0 -19
- package/docs/api/functions/index.joinPipe.html +0 -5
- package/docs/api/functions/index.keysPipe.html +0 -4
- package/docs/api/functions/index.lastPipe.html +0 -4
- package/docs/api/functions/index.lowercasePipe.html +0 -4
- package/docs/api/functions/index.mapFormToClass.html +0 -17
- package/docs/api/functions/index.matchRoute.html +0 -5
- package/docs/api/functions/index.navigate.html +0 -8
- package/docs/api/functions/index.onError.html +0 -8
- package/docs/api/functions/index.piecesPipe.html +0 -8
- package/docs/api/functions/index.post.html +0 -9
- package/docs/api/functions/index.printRoutes.html +0 -2
- package/docs/api/functions/index.put.html +0 -9
- package/docs/api/functions/index.readData.html +0 -17
- package/docs/api/functions/index.registerRouteTarget.html +0 -9
- package/docs/api/functions/index.reportError.html +0 -10
- package/docs/api/functions/index.request.html +0 -8
- package/docs/api/functions/index.resolveValue.html +0 -18
- package/docs/api/functions/index.setFetch.html +0 -6
- package/docs/api/functions/index.setFormData.html +0 -17
- package/docs/api/functions/index.shortenPipe.html +0 -5
- package/docs/api/functions/index.startRouting.html +0 -6
- package/docs/api/functions/index.ternaryPipe.html +0 -6
- package/docs/api/functions/index.trimPipe.html +0 -4
- package/docs/api/functions/index.unregisterRouteTarget.html +0 -3
- package/docs/api/functions/index.uppercasePipe.html +0 -4
- package/docs/api/hierarchy.html +0 -1
- package/docs/api/index.html +0 -323
- package/docs/api/interfaces/http.SimpleDataEvent.html +0 -3
- package/docs/api/interfaces/http.WebSocketAbstraction.html +0 -9
- package/docs/api/interfaces/http.WebSocketCodec.html +0 -4
- package/docs/api/interfaces/http.WebSocketOptions.html +0 -20
- package/docs/api/interfaces/index.CompiledTemplate.html +0 -10
- package/docs/api/interfaces/index.DataLoader.html +0 -19
- package/docs/api/interfaces/index.EngineConfig.html +0 -11
- package/docs/api/interfaces/index.ErrorContext.html +0 -4
- package/docs/api/interfaces/index.FormReaderOptions.html +0 -8
- package/docs/api/interfaces/index.HttpOptions.html +0 -16
- package/docs/api/interfaces/index.HttpResponse.html +0 -17
- package/docs/api/interfaces/index.LoadRoute.html +0 -7
- package/docs/api/interfaces/index.NavigateOptions.html +0 -7
- package/docs/api/interfaces/index.PipeRegistry.html +0 -12
- package/docs/api/interfaces/index.RegistrationOptions.html +0 -22
- package/docs/api/interfaces/index.RenderTemplate.html +0 -7
- package/docs/api/interfaces/index.RequestOptions.html +0 -11
- package/docs/api/interfaces/index.Routable.html +0 -10
- package/docs/api/interfaces/index.Route.html +0 -13
- package/docs/api/interfaces/index.RouteGuard.html +0 -2
- package/docs/api/interfaces/index.RouteValue.html +0 -6
- package/docs/api/interfaces/index.SSEOptions.html +0 -24
- package/docs/api/interfaces/index.ValidationContext.html +0 -8
- package/docs/api/interfaces/index.ValidatorOptions.html +0 -14
- package/docs/api/media/Architecture.md +0 -333
- package/docs/api/media/DependencyInjection.md +0 -277
- package/docs/api/media/GettingStarted.md +0 -231
- package/docs/api/media/HttpClient.md +0 -459
- package/docs/api/media/Pipes.md +0 -211
- package/docs/api/media/Routing.md +0 -332
- package/docs/api/media/WhyRelaxjs.md +0 -336
- package/docs/api/media/forms.md +0 -99
- package/docs/api/media/html.md +0 -175
- package/docs/api/media/i18n.md +0 -354
- package/docs/api/media/utilities.md +0 -143
- package/docs/api/media/validation.md +0 -351
- package/docs/api/modules/collections_Index.html +0 -1
- package/docs/api/modules/di.html +0 -1
- package/docs/api/modules/elements.html +0 -1
- package/docs/api/modules/forms.html +0 -1
- package/docs/api/modules/html.html +0 -1
- package/docs/api/modules/http.html +0 -1
- package/docs/api/modules/i18n.html +0 -1
- package/docs/api/modules/index.html +0 -1
- package/docs/api/modules/routing.html +0 -1
- package/docs/api/modules/utils.html +0 -1
- package/docs/api/modules.html +0 -1
- package/docs/api/types/http.WebSocketFactory.html +0 -2
- package/docs/api/types/i18n.MessageFormatter.html +0 -3
- package/docs/api/types/i18n.MissingTranslationHandler.html +0 -1
- package/docs/api/types/index.Constructor.html +0 -7
- package/docs/api/types/index.ConverterFunc.html +0 -2
- package/docs/api/types/index.DataType.html +0 -2
- package/docs/api/types/index.InputType.html +0 -2
- package/docs/api/types/index.PipeFunction.html +0 -6
- package/docs/api/types/index.RouteData.html +0 -1
- package/docs/api/types/index.RouteMatchResult.html +0 -9
- package/docs/api/types/index.RouteParamType.html +0 -1
- package/docs/api/types/index.RouteSegmentType.html +0 -2
- package/docs/api/types/index.SSEEventFactory.html +0 -5
- package/docs/api/types/index.ServiceScope.html +0 -10
- package/docs/api/types/index.SortColumn.html +0 -3
- package/docs/api/variables/i18n.formatICU.html +0 -3
- package/docs/api/variables/index.container.html +0 -6
- package/docs/api/variables/index.defaultPipes.html +0 -6
- package/docs/api/variables/index.internalRoutes.html +0 -1
- package/docs/api/variables/index.serviceCollection.html +0 -6
package/docs/api/media/Pipes.md
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
# Pipes
|
|
2
|
-
|
|
3
|
-
Data transformation functions for use in template expressions. Pipes transform values for display without modifying the underlying data.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
In templates with `compileTemplate`:
|
|
8
|
-
|
|
9
|
-
```html
|
|
10
|
-
<span>{{name | uppercase}}</span>
|
|
11
|
-
<span>{{price | currency}}</span>
|
|
12
|
-
<span>{{description | shorten:50}}</span>
|
|
13
|
-
<span>{{tags | join:, }}</span>
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Pipes can be chained:
|
|
17
|
-
|
|
18
|
-
```html
|
|
19
|
-
<span>{{text | trim | uppercase | shorten:20}}</span>
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Localization
|
|
23
|
-
|
|
24
|
-
Several pipes are locale-aware and use the [i18n](i18n/i18n.md) system:
|
|
25
|
-
|
|
26
|
-
- `currency` - Formats numbers according to locale
|
|
27
|
-
- `date` - Formats dates according to locale
|
|
28
|
-
- `daysAgo` - Translates "today", "yesterday", "X days ago"
|
|
29
|
-
- `pieces` - Translates piece counts
|
|
30
|
-
|
|
31
|
-
To use localized pipes:
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
import { setLocale, loadNamespace } from '@relax.js/core/i18n';
|
|
35
|
-
|
|
36
|
-
// Set locale and load pipe translations
|
|
37
|
-
await setLocale('sv');
|
|
38
|
-
await loadNamespace('r-pipes');
|
|
39
|
-
|
|
40
|
-
// Now pipes will output Swedish
|
|
41
|
-
// {{createdAt | daysAgo}} → "idag", "igår", "3 dagar sedan"
|
|
42
|
-
// {{price | currency:SEK}} → "1 234,56 kr"
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Translation Keys
|
|
46
|
-
|
|
47
|
-
Translation keys in the `r-pipes` namespace:
|
|
48
|
-
|
|
49
|
-
| Key | Message (EN) | Message (SV) |
|
|
50
|
-
|-----|-------------|-------------|
|
|
51
|
-
| `today` | `today` | `idag` |
|
|
52
|
-
| `yesterday` | `yesterday` | `igår` |
|
|
53
|
-
| `daysAgo` | `{count, plural, one {# day ago} other {# days ago}}` | `{count, plural, one {# dag sedan} other {# dagar sedan}}` |
|
|
54
|
-
| `pieces` | `{count, plural, =0 {none} one {one} other {# pcs}}` | `{count, plural, =0 {inga} one {en} other {# st}}` |
|
|
55
|
-
|
|
56
|
-
### Translation Files
|
|
57
|
-
|
|
58
|
-
Pipe translations are stored in `src/i18n/locales/{locale}/r-pipes.json`:
|
|
59
|
-
|
|
60
|
-
```json
|
|
61
|
-
{
|
|
62
|
-
"today": "today",
|
|
63
|
-
"yesterday": "yesterday",
|
|
64
|
-
"daysAgo": "{count, plural, one {# day ago} other {# days ago}}",
|
|
65
|
-
"pieces": "{count, plural, =0 {none} one {one} other {# pcs}}"
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
To add a new locale, create `src/i18n/locales/{locale}/r-pipes.json` with the translated strings.
|
|
70
|
-
|
|
71
|
-
## Programmatic Usage
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { applyPipes, defaultPipes, createPipeRegistry } from '@relax.js/core/utils';
|
|
75
|
-
|
|
76
|
-
// Apply pipes to a value
|
|
77
|
-
const result = applyPipes('hello world', ['uppercase', 'shorten:8']);
|
|
78
|
-
// Returns: 'HELLO...'
|
|
79
|
-
|
|
80
|
-
// Use the default registry directly
|
|
81
|
-
const upper = defaultPipes.get('uppercase');
|
|
82
|
-
console.log(upper('hello')); // 'HELLO'
|
|
83
|
-
|
|
84
|
-
// Create a fresh registry
|
|
85
|
-
const registry = createPipeRegistry();
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Built-in Pipes
|
|
89
|
-
|
|
90
|
-
### Text
|
|
91
|
-
|
|
92
|
-
| Pipe | Description | Example | Result |
|
|
93
|
-
|------|-------------|---------|--------|
|
|
94
|
-
| `uppercase` | Convert to uppercase | `{{"hello" \| uppercase}}` | `HELLO` |
|
|
95
|
-
| `lowercase` | Convert to lowercase | `{{"HELLO" \| lowercase}}` | `hello` |
|
|
96
|
-
| `capitalize` | Capitalize first letter | `{{"hello" \| capitalize}}` | `Hello` |
|
|
97
|
-
| `trim` | Remove leading/trailing whitespace | `{{" hello " \| trim}}` | `hello` |
|
|
98
|
-
| `shorten:n` | Limit to n characters with ellipsis | `{{"hello world" \| shorten:8}}` | `hello...` |
|
|
99
|
-
|
|
100
|
-
### Formatting (Locale-Aware)
|
|
101
|
-
|
|
102
|
-
These pipes use the current i18n locale for formatting.
|
|
103
|
-
|
|
104
|
-
| Pipe | Description | Example | en | sv |
|
|
105
|
-
|------|-------------|---------|----|----|
|
|
106
|
-
| `currency` | Format as currency (default USD) | `{{1234.5 \| currency}}` | `$1,234.50` | `1 234,50 US$` |
|
|
107
|
-
| `currency:CODE` | Format with specific currency | `{{1234.5 \| currency:SEK}}` | `SEK 1,234.50` | `1 234,50 kr` |
|
|
108
|
-
| `date` | Format date (ISO) | `{{date \| date}}` | `2024-01-15T...` | `2024-01-15T...` |
|
|
109
|
-
| `date:short` | Short date format | `{{date \| date:short}}` | `1/15/2024` | `2024-01-15` |
|
|
110
|
-
| `date:long` | Long date format | `{{date \| date:long}}` | `Monday, January 15, 2024` | `måndag 15 januari 2024` |
|
|
111
|
-
| `daysAgo` | Relative date | `{{date \| daysAgo}}` | `3 days ago` | `3 dagar sedan` |
|
|
112
|
-
| `pieces` | Piece count | `{{3 \| pieces}}` | `3 pcs` | `3 st` |
|
|
113
|
-
|
|
114
|
-
### Arrays
|
|
115
|
-
|
|
116
|
-
| Pipe | Description | Example | Result |
|
|
117
|
-
|------|-------------|---------|--------|
|
|
118
|
-
| `join` | Join with comma | `{{tags \| join}}` | `a,b,c` |
|
|
119
|
-
| `join:sep` | Join with custom separator | `{{tags \| join: \| }}` | `a \| b \| c` |
|
|
120
|
-
| `first` | Get first element | `{{items \| first}}` | First item |
|
|
121
|
-
| `last` | Get last element | `{{items \| last}}` | Last item |
|
|
122
|
-
|
|
123
|
-
### Objects
|
|
124
|
-
|
|
125
|
-
| Pipe | Description | Example | Result |
|
|
126
|
-
|------|-------------|---------|--------|
|
|
127
|
-
| `keys` | Get object keys as array | `{{user \| keys}}` | `["name", "email"]` |
|
|
128
|
-
|
|
129
|
-
### Conditionals
|
|
130
|
-
|
|
131
|
-
| Pipe | Description | Example | Result |
|
|
132
|
-
|------|-------------|---------|--------|
|
|
133
|
-
| `default:val` | Fallback for falsy values | `{{name \| default:Anonymous}}` | Value or `Anonymous` |
|
|
134
|
-
| `ternary:t:f` | Conditional value | `{{active \| ternary:Yes:No}}` | `Yes` or `No` |
|
|
135
|
-
|
|
136
|
-
## Pipe Arguments
|
|
137
|
-
|
|
138
|
-
Arguments are passed after a colon:
|
|
139
|
-
|
|
140
|
-
```html
|
|
141
|
-
<!-- Single argument -->
|
|
142
|
-
<span>{{text | shorten:50}}</span>
|
|
143
|
-
<span>{{price | currency:EUR}}</span>
|
|
144
|
-
|
|
145
|
-
<!-- Multiple arguments -->
|
|
146
|
-
<span>{{status | ternary:Active:Inactive}}</span>
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Configuration
|
|
150
|
-
|
|
151
|
-
Pass a pipe registry to `compileTemplate`:
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
import { compileTemplate } from '@relax.js/core/html';
|
|
155
|
-
import { createPipeRegistry } from '@relax.js/core/utils';
|
|
156
|
-
|
|
157
|
-
const pipeRegistry = createPipeRegistry();
|
|
158
|
-
const { content, render } = compileTemplate(
|
|
159
|
-
'<span>{{name | uppercase}}</span>',
|
|
160
|
-
{ strict: false, pipeRegistry }
|
|
161
|
-
);
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## API Reference
|
|
165
|
-
|
|
166
|
-
### Types
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
type PipeFunction = (value: any, ...args: any[]) => any;
|
|
170
|
-
|
|
171
|
-
interface PipeRegistry {
|
|
172
|
-
lookup(name: string): PipeFunction | null;
|
|
173
|
-
get(name: string): PipeFunction; // Throws if not found
|
|
174
|
-
has(name: string): boolean;
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Functions
|
|
179
|
-
|
|
180
|
-
| Function | Description |
|
|
181
|
-
|----------|-------------|
|
|
182
|
-
| `createPipeRegistry()` | Create a new registry with all built-in pipes |
|
|
183
|
-
| `applyPipes(value, pipes, registry?)` | Apply an array of pipe strings to a value |
|
|
184
|
-
| `defaultPipes` | Pre-created registry instance |
|
|
185
|
-
|
|
186
|
-
### Individual Pipe Functions
|
|
187
|
-
|
|
188
|
-
All pipes are also exported as individual functions for direct use:
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
import {
|
|
192
|
-
uppercasePipe,
|
|
193
|
-
lowercasePipe,
|
|
194
|
-
capitalizePipe,
|
|
195
|
-
trimPipe,
|
|
196
|
-
shortenPipe,
|
|
197
|
-
currencyPipe,
|
|
198
|
-
datePipe,
|
|
199
|
-
daysAgoPipe,
|
|
200
|
-
piecesPipe,
|
|
201
|
-
joinPipe,
|
|
202
|
-
firstPipe,
|
|
203
|
-
lastPipe,
|
|
204
|
-
keysPipe,
|
|
205
|
-
defaultPipe,
|
|
206
|
-
ternaryPipe
|
|
207
|
-
} from '@relax.js/core/utils';
|
|
208
|
-
|
|
209
|
-
const result = uppercasePipe('hello'); // 'HELLO'
|
|
210
|
-
const formatted = currencyPipe(1234.56); // '$1,234.56' (depends on locale)
|
|
211
|
-
```
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
# Routing
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
A client-side routing system for single-page applications. The router:
|
|
6
|
-
|
|
7
|
-
- Matches URLs to route configurations
|
|
8
|
-
- Extracts typed parameters from URL segments
|
|
9
|
-
- Manages browser history (back/forward navigation)
|
|
10
|
-
- Dispatches `NavigateRouteEvent` to render components
|
|
11
|
-
- Supports multiple rendering targets (main content, sidebars, modals)
|
|
12
|
-
- Handles layout switching between different HTML shells
|
|
13
|
-
|
|
14
|
-
The router itself only handles matching and navigation. Rendering is handled by [`<r-route-target>`](RoutingTarget.md) components that listen for navigation events.
|
|
15
|
-
|
|
16
|
-
## Quick Start
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
import { Route, defineRoutes, startRouting } from '@relax.js/core/routing';
|
|
20
|
-
|
|
21
|
-
const routes: Route[] = [
|
|
22
|
-
{ name: 'home', path: '/', componentTagName: 'home-page' },
|
|
23
|
-
{ name: 'users', path: '/users', componentTagName: 'user-list' },
|
|
24
|
-
{ name: 'user', path: '/users/:id', componentTagName: 'user-profile' },
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
defineRoutes(routes);
|
|
28
|
-
startRouting();
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
```html
|
|
32
|
-
<body>
|
|
33
|
-
<nav>
|
|
34
|
-
<r-link name="home">Home</r-link>
|
|
35
|
-
<r-link name="users">Users</r-link>
|
|
36
|
-
</nav>
|
|
37
|
-
<main>
|
|
38
|
-
<r-route-target></r-route-target>
|
|
39
|
-
</main>
|
|
40
|
-
</body>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Route Definition
|
|
44
|
-
|
|
45
|
-
Each route specifies how a URL maps to a component:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
interface Route {
|
|
49
|
-
name?: string; // Identifier for programmatic navigation
|
|
50
|
-
path: string; // URL pattern with parameters
|
|
51
|
-
componentTagName?: string; // Custom element tag name
|
|
52
|
-
component?: WebComponentConstructor; // Or class reference
|
|
53
|
-
target?: string; // Named r-route-target (default: unnamed)
|
|
54
|
-
layout?: string; // HTML file for different shells
|
|
55
|
-
guards?: RouteGuard[]; // Access control
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### URL Pattern Syntax
|
|
60
|
-
|
|
61
|
-
| Syntax | Type | Example | Matches |
|
|
62
|
-
|--------|------|---------|---------|
|
|
63
|
-
| `text` | Static segment | `/users` | Exactly "users" |
|
|
64
|
-
| `:name` | String parameter | `/users/:id` | `/users/john` → `{ id: 'john' }` |
|
|
65
|
-
| `;name` | Number parameter | `/orders/;orderId` | `/orders/123` → `{ orderId: 123 }` |
|
|
66
|
-
|
|
67
|
-
Number parameters (`;`) validate that the segment contains only digits and convert to `number` type. String parameters (`:`) accept any value and remain as `string`.
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
const routes: Route[] = [
|
|
71
|
-
{ name: 'home', path: '/' },
|
|
72
|
-
{ name: 'user', path: '/users/:userName' }, // String: userName
|
|
73
|
-
{ name: 'order', path: '/orders/;orderId' }, // Number: orderId
|
|
74
|
-
{ name: 'category', path: '/shop/:category/items' }, // Mixed static + param
|
|
75
|
-
];
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Navigation
|
|
79
|
-
|
|
80
|
-
### Using RouteLink Component
|
|
81
|
-
|
|
82
|
-
The simplest way to navigate is with [`<r-link>`](RouteLink.md):
|
|
83
|
-
|
|
84
|
-
```html
|
|
85
|
-
<r-link name="home">Home</r-link>
|
|
86
|
-
<r-link name="user" param-userName="john">View Profile</r-link>
|
|
87
|
-
<r-link name="order" param-orderId="123">Order Details</r-link>
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Programmatic Navigation
|
|
91
|
-
|
|
92
|
-
Use `navigate()` for navigation from code:
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { navigate } from '@relax.js/core/routing';
|
|
96
|
-
|
|
97
|
-
// By route name with parameters
|
|
98
|
-
navigate('user', { params: { userName: 'john' } });
|
|
99
|
-
navigate('order', { params: { orderId: 123 } });
|
|
100
|
-
|
|
101
|
-
// By URL directly
|
|
102
|
-
navigate('/users/john');
|
|
103
|
-
navigate('/orders/123');
|
|
104
|
-
|
|
105
|
-
// To a specific target
|
|
106
|
-
navigate('preview', { params: { id: '42' }, target: 'modal' });
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Multiple Targets
|
|
110
|
-
|
|
111
|
-
Routes can render in different [`<r-route-target>`](RoutingTarget.md) elements:
|
|
112
|
-
|
|
113
|
-
```html
|
|
114
|
-
<div class="layout">
|
|
115
|
-
<aside>
|
|
116
|
-
<r-route-target name="sidebar"></r-route-target>
|
|
117
|
-
</aside>
|
|
118
|
-
<main>
|
|
119
|
-
<r-route-target></r-route-target>
|
|
120
|
-
</main>
|
|
121
|
-
</div>
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
const routes: Route[] = [
|
|
126
|
-
{ name: 'home', path: '/', componentTagName: 'home-page' },
|
|
127
|
-
{ name: 'menu', path: '/menu', target: 'sidebar', componentTagName: 'nav-menu' },
|
|
128
|
-
];
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Routes without a `target` property render in the default (unnamed) target.
|
|
132
|
-
|
|
133
|
-
## Browser History
|
|
134
|
-
|
|
135
|
-
The router integrates with the browser's History API:
|
|
136
|
-
|
|
137
|
-
- `navigate()` calls `history.pushState()` to add entries
|
|
138
|
-
- Back/forward buttons trigger navigation to previous routes (components receive `loadRoute` again)
|
|
139
|
-
- `startRouting()` reads the current URL and navigates on page load
|
|
140
|
-
|
|
141
|
-
URLs display the route path (e.g., `/users/john`), not the HTML file.
|
|
142
|
-
|
|
143
|
-
## Layouts
|
|
144
|
-
|
|
145
|
-
Different parts of your application may need different HTML shells (navigation, sidebar presence, etc.). See [Layouts](layouts.md) for details.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
const routes: Route[] = [
|
|
149
|
-
{ name: 'login', path: '/login', componentTagName: 'login-page', layout: 'public' },
|
|
150
|
-
{ name: 'dashboard', path: '/dashboard', componentTagName: 'dashboard-page' }, // default layout
|
|
151
|
-
];
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
When navigating between layouts, the router redirects to the appropriate HTML file and resumes navigation.
|
|
155
|
-
|
|
156
|
-
## Route Guards
|
|
157
|
-
|
|
158
|
-
Guards control access to routes:
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
import { RouteGuard, GuardResult, RouteMatchResult } from '@relax.js/core/routing';
|
|
162
|
-
|
|
163
|
-
class AuthGuard implements RouteGuard {
|
|
164
|
-
check(route: RouteMatchResult): GuardResult {
|
|
165
|
-
if (isAuthenticated()) {
|
|
166
|
-
return GuardResult.Continue; // Check other guards
|
|
167
|
-
}
|
|
168
|
-
navigate('login');
|
|
169
|
-
return GuardResult.Stop; // Prevent navigation
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const routes: Route[] = [
|
|
174
|
-
{ name: 'dashboard', path: '/dashboard', componentTagName: 'dashboard-page', guards: [new AuthGuard()] },
|
|
175
|
-
];
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Guard Results
|
|
179
|
-
|
|
180
|
-
| Result | Behavior |
|
|
181
|
-
|--------|----------|
|
|
182
|
-
| `Allow` | Proceed immediately, skip remaining guards |
|
|
183
|
-
| `Continue` | Check next guard (or proceed if none left) |
|
|
184
|
-
| `Stop` | Cancel navigation silently |
|
|
185
|
-
| `Deny` | Cancel navigation and throw `RouteGuardError` |
|
|
186
|
-
|
|
187
|
-
## Events
|
|
188
|
-
|
|
189
|
-
Navigation dispatches `NavigateRouteEvent` on `document`:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
import { NavigateRouteEvent } from '@relax.js/core/routing';
|
|
193
|
-
|
|
194
|
-
document.addEventListener('rlx.navigateRoute', (e: NavigateRouteEvent) => {
|
|
195
|
-
console.log('Route:', e.route.name);
|
|
196
|
-
console.log('Params:', e.routeData);
|
|
197
|
-
console.log('Target:', e.routeTarget ?? 'default');
|
|
198
|
-
});
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
This event is typed in `HTMLElementEventMap` for full TypeScript support.
|
|
202
|
-
|
|
203
|
-
## Route Matching
|
|
204
|
-
|
|
205
|
-
For advanced use cases, match routes without navigating:
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
import { matchRoute, findRouteByUrl, findRouteByName } from '@relax.js/core/routing';
|
|
209
|
-
|
|
210
|
-
// Match by URL
|
|
211
|
-
const result = matchRoute(routes, '/users/john');
|
|
212
|
-
// { route: {...}, params: { userName: 'john' }, urlSegments: ['users', 'john'] }
|
|
213
|
-
|
|
214
|
-
// Match by name
|
|
215
|
-
const result = matchRoute(routes, 'user', { userName: 'john' });
|
|
216
|
-
|
|
217
|
-
// Direct functions
|
|
218
|
-
findRouteByUrl(routes, '/users/john');
|
|
219
|
-
findRouteByName(routes, 'user', { userName: 'john' });
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
## Receiving Route Parameters
|
|
223
|
-
|
|
224
|
-
Components rendered by `<r-route-target>` can receive route parameters in two ways.
|
|
225
|
-
|
|
226
|
-
### loadRoute (async initialization)
|
|
227
|
-
|
|
228
|
-
Implement `loadRoute()` to run async setup before the component is added to the DOM. The component is not visible until `loadRoute()` completes.
|
|
229
|
-
|
|
230
|
-
```typescript
|
|
231
|
-
import { LoadRoute, RouteData } from '@relax.js/core/routing';
|
|
232
|
-
|
|
233
|
-
class OrderDetail extends HTMLElement implements LoadRoute<{ orderId: number }> {
|
|
234
|
-
private order: Order;
|
|
235
|
-
|
|
236
|
-
async loadRoute(data: { orderId: number }) {
|
|
237
|
-
this.order = await fetchOrder(data.orderId);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
connectedCallback() {
|
|
241
|
-
this.render(this.order);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### routeData (typed property)
|
|
247
|
-
|
|
248
|
-
Implement `Routable` to receive parameters as a typed property. The property is optional since it's set by the router after construction.
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
import { Routable } from '@relax.js/core/routing';
|
|
252
|
-
|
|
253
|
-
class UserProfile extends HTMLElement implements Routable<{ userName: string }> {
|
|
254
|
-
routeData?: { userName: string };
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
For convention-based usage without the interface, declare `routeData` directly on your component. The router always assigns it regardless.
|
|
259
|
-
|
|
260
|
-
Both can be combined. `loadRoute()` runs first, then `routeData` is assigned.
|
|
261
|
-
|
|
262
|
-
## Error Handling
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
import { RouteError, RouteGuardError } from '@relax.js/core/routing';
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
navigate('unknown-route');
|
|
269
|
-
} catch (e) {
|
|
270
|
-
if (e instanceof RouteGuardError) {
|
|
271
|
-
console.log('Access denied');
|
|
272
|
-
} else if (e instanceof RouteError) {
|
|
273
|
-
console.log('Route not found');
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
When no route matches, the error message lists all available routes for debugging.
|
|
279
|
-
|
|
280
|
-
Routing errors are reported through the global [error handler](../Errors.md). The error context contains:
|
|
281
|
-
|
|
282
|
-
| Field | Description |
|
|
283
|
-
|-------|-------------|
|
|
284
|
-
| `route` | Route name |
|
|
285
|
-
| `componentTagName` | Custom element tag name |
|
|
286
|
-
| `component` | Component class name (if using class reference) |
|
|
287
|
-
| `routeData` | Parameters extracted from the URL |
|
|
288
|
-
|
|
289
|
-
## API Reference
|
|
290
|
-
|
|
291
|
-
### Functions
|
|
292
|
-
|
|
293
|
-
| Function | Description |
|
|
294
|
-
|----------|-------------|
|
|
295
|
-
| `defineRoutes(routes)` | Register routes at startup |
|
|
296
|
-
| `startRouting()` | Initialize router and navigate to current URL |
|
|
297
|
-
| `navigate(nameOrUrl, options?)` | Navigate to a route |
|
|
298
|
-
| `matchRoute(routes, nameOrUrl, params?)` | Match without navigating |
|
|
299
|
-
| `findRouteByUrl(routes, path)` | Match by URL pattern |
|
|
300
|
-
| `findRouteByName(routes, name, params)` | Match by route name |
|
|
301
|
-
|
|
302
|
-
### Types
|
|
303
|
-
|
|
304
|
-
```typescript
|
|
305
|
-
type RouteParamType = string | number;
|
|
306
|
-
type RouteData = Record<string, RouteParamType>;
|
|
307
|
-
|
|
308
|
-
interface NavigateOptions {
|
|
309
|
-
params?: Record<string, string | number>;
|
|
310
|
-
target?: string;
|
|
311
|
-
routes?: Route[]; // Override registered routes
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
interface RouteMatchResult {
|
|
315
|
-
route: Route;
|
|
316
|
-
params: RouteData;
|
|
317
|
-
urlSegments: string[];
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
enum GuardResult {
|
|
321
|
-
Allow, // Proceed, skip remaining guards
|
|
322
|
-
Deny, // Throw RouteGuardError
|
|
323
|
-
Continue, // Check next guard
|
|
324
|
-
Stop // Cancel silently
|
|
325
|
-
}
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
## Related
|
|
329
|
-
|
|
330
|
-
- [`<r-route-target>`](RoutingTarget.md) - Renders routed components
|
|
331
|
-
- [`<r-link>`](RouteLink.md) - Declarative navigation links
|
|
332
|
-
- [Layouts](layouts.md) - Multiple HTML shells
|