@reforgium/internal 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,42 +6,255 @@
|
|
|
6
6
|
**Core infrastructure package for Angular (20+) applications.**
|
|
7
7
|
|
|
8
8
|
`@reforgium/internal` is a foundational layer that sits *under* feature libraries and applications.
|
|
9
|
-
It provides shared models, DI tokens, and low-level utilities designed for reuse, consistency, and long-term maintainability.
|
|
9
|
+
It provides shared models, typed DI tokens, and low-level utilities designed for reuse, consistency, and long-term maintainability.
|
|
10
10
|
|
|
11
11
|
This package is **not** a UI kit and **not** a framework replacement.
|
|
12
12
|
It is a **stable internal contract** for building scalable Angular systems.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Why
|
|
17
17
|
|
|
18
18
|
- Centralize shared domain primitives
|
|
19
|
-
-
|
|
20
|
-
- Keep feature
|
|
19
|
+
- Prevent cross-package circular dependencies
|
|
20
|
+
- Keep feature/UI layers clean
|
|
21
21
|
- Enable aggressive tree-shaking and dead-code elimination
|
|
22
|
-
-
|
|
22
|
+
- Provide a reusable internal base across multiple libraries and apps
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## What’s inside
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
- **Models** — shared domain models, interfaces, and value objects
|
|
29
|
+
- **Tokens** — typed DI tokens for configuration and infrastructure contracts
|
|
30
|
+
- **Utilities** — framework-agnostic helpers and low-level utilities (including Signal-friendly helpers)
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
Shared domain models, interfaces, and value objects.
|
|
32
|
+
> It’s the bedrock, not the building.
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm i @reforgium/internal
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Public API
|
|
45
|
+
|
|
46
|
+
## Models
|
|
47
|
+
|
|
48
|
+
### Component models (`components.ts`)
|
|
49
|
+
|
|
50
|
+
#### `Appearance`
|
|
51
|
+
Preset UI appearance tokens.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import type { Appearance } from '@reforgium/internal';
|
|
55
|
+
|
|
56
|
+
const appearance: Appearance = 'primary';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### `SelectOption`
|
|
60
|
+
Basic select option shape: `{ label: string; value: string | number }`.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import type { SelectOption } from '@reforgium/internal';
|
|
64
|
+
|
|
65
|
+
const options: SelectOption[] = [
|
|
66
|
+
{ label: 'Admin', value: 'admin' },
|
|
67
|
+
{ label: 'User', value: 'user' },
|
|
68
|
+
];
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### `SelectIconOption extends SelectOption`
|
|
72
|
+
Select option with an icon: `icon: string`.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import type { SelectIconOption } from '@reforgium/internal';
|
|
76
|
+
|
|
77
|
+
const langOptions: SelectIconOption[] = [
|
|
78
|
+
{ value: 'en', label: 'English', icon: 'flag-en' },
|
|
79
|
+
{ value: 'ru', label: 'Рус', icon: 'flag-ru' },
|
|
80
|
+
];
|
|
81
|
+
```
|
|
35
82
|
|
|
36
|
-
|
|
37
|
-
Framework-agnostic helpers and low-level utilities.
|
|
83
|
+
### Utility types (`util.ts`)
|
|
38
84
|
|
|
85
|
+
#### `AnyType`
|
|
86
|
+
Compatibility type (similar to `any`) used in low-level helpers.
|
|
39
87
|
|
|
40
|
-
|
|
88
|
+
#### `AnyDict`
|
|
89
|
+
Compatibility dict type (similar to `Record<string, any>`) used across infra/helpers.
|
|
90
|
+
|
|
91
|
+
#### `LiteralOf<T>`
|
|
92
|
+
Returns a union of literal keys of an object type.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import type { LiteralOf } from '@reforgium/internal';
|
|
96
|
+
|
|
97
|
+
type StatusMap = { new: 1; done: 2 };
|
|
98
|
+
type StatusCode = LiteralOf<StatusMap>; // 'new' | 'done'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### `ValueOf<T>`
|
|
102
|
+
Returns a union of values of an object type.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import type { ValueOf } from '@reforgium/internal';
|
|
106
|
+
|
|
107
|
+
type StatusMap = { new: 1; done: 2 };
|
|
108
|
+
type StatusCode = ValueOf<StatusMap>; // 1 | 2
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### `Nullable<T>`
|
|
112
|
+
Returns a nullable copy of an object type.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import type { Nullable } from '@reforgium/internal';
|
|
116
|
+
|
|
117
|
+
type StatusMap = { new: number; done: number };
|
|
118
|
+
type StatusCode = Nullable<StatusMap>; // { new: number | null; done: number | null }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### API & pagination models (`api.ts`)
|
|
122
|
+
|
|
123
|
+
- `RestMethods` — `'GET' | 'POST' | 'PUT' | 'DELETE'`
|
|
124
|
+
- `PageableRequest` — `{ page: number; size?: number; sort?: string }`
|
|
125
|
+
- `PageableResponse<T>` — `content: T[]` + paging metadata
|
|
126
|
+
- `ErrorResponse` — `{ errorCode: number; message: string; fields: Record<string, string> }`
|
|
127
|
+
- `QueryParams<T>` — `page?`, `size?`, `sort?`, `filters?: Partial<T>`
|
|
128
|
+
- `Params` — route/query params dict
|
|
129
|
+
|
|
130
|
+
Example (typing only):
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import type { PageableRequest, QueryParams } from '@reforgium/internal';
|
|
134
|
+
|
|
135
|
+
const params: QueryParams<{ role: string }> = {
|
|
136
|
+
page: 0,
|
|
137
|
+
size: 20,
|
|
138
|
+
filters: { role: 'admin' },
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const asPageable: PageableRequest = {
|
|
142
|
+
page: params.page ?? 0,
|
|
143
|
+
size: params.size,
|
|
144
|
+
sort: params.sort,
|
|
145
|
+
};
|
|
146
|
+
```
|
|
41
147
|
|
|
42
148
|
---
|
|
43
149
|
|
|
44
|
-
##
|
|
150
|
+
## Tokens
|
|
151
|
+
The localization system is built around a service that manages translations across different languages and namespaces. It supports:
|
|
45
152
|
|
|
46
|
-
|
|
47
|
-
|
|
153
|
+
- Multiple languages (Russian 'ru', Kyrgyz 'kg'/'ky')
|
|
154
|
+
- Namespace-based translation loading
|
|
155
|
+
- Dynamic language switching with persistence
|
|
156
|
+
- Translation caching for performance
|
|
157
|
+
- Parameter interpolation in translations
|
|
158
|
+
- Reactive translation updates using Angular signals
|
|
159
|
+
|
|
160
|
+
## Utilities
|
|
161
|
+
|
|
162
|
+
### Dates (`date.utils.ts`)
|
|
163
|
+
|
|
164
|
+
- `formatDate(date, format = 'yyyy-MM-dd')`
|
|
165
|
+
- `formatToLocaledDate(date)` (ru-RU localized format)
|
|
166
|
+
- `parseToDate(value, format = 'dd.MM.yyyy')`
|
|
167
|
+
- `parseToDatePeriod(value, format = 'dd.MM.yyyy')`
|
|
168
|
+
- `isDatePeriod(value)`
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { formatDate, parseToDatePeriod } from '@reforgium/internal';
|
|
172
|
+
|
|
173
|
+
formatDate(new Date(2025, 0, 2), 'dd.MM.yyyy'); // '02.01.2025'
|
|
174
|
+
parseToDatePeriod('01.01.2025 - 31.01.2025'); // [Date, Date]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Formatting (`format.utils.ts`)
|
|
178
|
+
|
|
179
|
+
- `formatToSpacedNumber(num)` — thousand separators
|
|
180
|
+
- `truncate(text, limit)`
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { formatToSpacedNumber, truncate } from '@reforgium/internal';
|
|
184
|
+
|
|
185
|
+
formatToSpacedNumber(1234567); // '1 234 567'
|
|
186
|
+
truncate('Very long text', 8); // 'Very lon…'
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Routes & query (`routes.utils.ts`, `types.utils.ts`)
|
|
190
|
+
Sources: `src/common/utils/routes.utils.ts`, `src/common/utils/types.utils.ts`
|
|
191
|
+
|
|
192
|
+
- `makeQuery(object, concatType: 'comma' | 'json' | 'multi')`
|
|
193
|
+
- `materializeRoutePath(actualRoute, pureRoute)`
|
|
194
|
+
- `compareRoutes(actualRoute, pureRoute, withSubroute = false)`
|
|
195
|
+
- `parseQueryArray(val, mode, key?)`
|
|
196
|
+
- `concatArray(value, mode, key?)`
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { makeQuery, compareRoutes } from '@reforgium/internal';
|
|
200
|
+
|
|
201
|
+
makeQuery({ a: 1, b: [1, 2] }, 'comma'); // 'a=1&b=1,2'
|
|
202
|
+
compareRoutes('/users/42', '/users/:id'); // true
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Signal timers (`times.utils.ts`)
|
|
206
|
+
|
|
207
|
+
- `debounceSignal(src, ms = 150, opts?)`
|
|
208
|
+
- `throttleSignal(src, ms = 100, opts?)`
|
|
209
|
+
|
|
210
|
+
### Web helpers (`web.utils.ts`)
|
|
211
|
+
|
|
212
|
+
- `downloadFile(blob, fileName?)`
|
|
213
|
+
- `downloadUrl(url, fileName?)`
|
|
214
|
+
- `copyText(text)`
|
|
215
|
+
- `base64ToBlob(base64, mimeType = '')`
|
|
216
|
+
|
|
217
|
+
### DOM (`available-height.utils.ts`)
|
|
218
|
+
|
|
219
|
+
- `getAvailableHeight(el, margin = 20)`
|
|
220
|
+
|
|
221
|
+
### Positioning (`positions.utils.ts`)
|
|
222
|
+
|
|
223
|
+
- `getCorrectedPosition(anchor, triggerSize, boundBox, directions, offset)`
|
|
224
|
+
|
|
225
|
+
### Object access (`get-chained-value.utils.ts`)
|
|
226
|
+
|
|
227
|
+
- `getChainedValue(obj, path)`
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import { getChainedValue } from '@reforgium/internal';
|
|
231
|
+
|
|
232
|
+
getChainedValue({ a: { b: [{ c: 1 }] } }, 'a.b.0.c'); // 1
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Deep compare (`deep-equal.utils.ts`)
|
|
236
|
+
|
|
237
|
+
- `deepEqual(a, b)` (supports Map/Set/Date/RegExp/NaN, cycle-safe)
|
|
238
|
+
|
|
239
|
+
### Type guards (`types.utils.ts`)
|
|
240
|
+
|
|
241
|
+
- `isNullable(value, withEmptyString = false)`
|
|
242
|
+
- `isNumber(value, fromString = false)`
|
|
243
|
+
- `isObject(val)`
|
|
244
|
+
|
|
245
|
+
### Misc (`generate.utils.ts`)
|
|
246
|
+
|
|
247
|
+
- `generateId(limit = 15, radix = 36)`
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { generateId } from '@reforgium/internal';
|
|
251
|
+
|
|
252
|
+
generateId(); // e.g. 'k3f9mz72q'
|
|
253
|
+
generateId(10, 16); // hex-like
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT
|
|
@@ -1,25 +1,74 @@
|
|
|
1
1
|
import { InjectionToken, signal, effect, untracked } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Injection token for the current application language as a Signal.
|
|
5
|
+
* Provides reactive access to the currently selected language.
|
|
6
|
+
* Can be overridden in app.config with a custom provider.
|
|
7
|
+
*
|
|
8
|
+
* @type {InjectionToken<Signal<Langs>>}
|
|
6
9
|
*/
|
|
7
10
|
const SELECTED_LANG = new InjectionToken('RE_SELECTED_LANG');
|
|
11
|
+
/**
|
|
12
|
+
* Injection token for language change provider.
|
|
13
|
+
* Provides access to method for changing the current application language.
|
|
14
|
+
* Can be overridden in app.config with a custom provider.
|
|
15
|
+
*
|
|
16
|
+
* @type {InjectionToken<ChangeLangProvider>}
|
|
17
|
+
*/
|
|
18
|
+
const CHANGE_LANG = new InjectionToken('RE_CHANGE_LANG');
|
|
19
|
+
/**
|
|
20
|
+
* Injection token for translation provider.
|
|
21
|
+
* Provides access to translation methods for message retrieval and namespace loading.
|
|
22
|
+
*
|
|
23
|
+
* @type {InjectionToken<TranslationProvider>}
|
|
24
|
+
*/
|
|
25
|
+
const TRANSLATION = new InjectionToken('RE_GET_LANG');
|
|
8
26
|
|
|
9
27
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
28
|
+
* Current application theme as Signal.
|
|
29
|
+
* Can be overridden in app.config with a custom provider.
|
|
12
30
|
*/
|
|
13
31
|
const SELECTED_THEME = new InjectionToken('RE_SELECTED_THEME');
|
|
32
|
+
const CHANGE_THEME = new InjectionToken('RE_CHANGE_THEME');
|
|
14
33
|
|
|
15
34
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
35
|
+
* Injection token for the current device type as a Signal.
|
|
36
|
+
*
|
|
37
|
+
* Provides reactive access to the current device type throughout the application.
|
|
38
|
+
* Can be overridden in app.config with a custom provider to supply device detection logic.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* // In app.config.ts
|
|
43
|
+
* providers: [
|
|
44
|
+
* {
|
|
45
|
+
* provide: CURRENT_DEVICE,
|
|
46
|
+
* useValue: signal<Devices>('mobile')
|
|
47
|
+
* }
|
|
48
|
+
* ]
|
|
49
|
+
*
|
|
50
|
+
* // In a component or service
|
|
51
|
+
* private readonly currentDevice = inject(CURRENT_DEVICE);
|
|
52
|
+
* ```
|
|
18
53
|
*/
|
|
19
54
|
const CURRENT_DEVICE = new InjectionToken('RE_CURRENT_DEVICE');
|
|
20
55
|
|
|
21
56
|
/**
|
|
22
|
-
*
|
|
57
|
+
* Injection token for a validation messages map.
|
|
58
|
+
* Can be overridden in feature modules to provide custom validation messages.
|
|
59
|
+
* Defaults to an empty object when not provided.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // In a feature module:
|
|
63
|
+
* providers: [
|
|
64
|
+
* {
|
|
65
|
+
* provide: VALIDATION_MESSAGES,
|
|
66
|
+
* useValue: {
|
|
67
|
+
* required: () => 'This field is required',
|
|
68
|
+
* minlength: (error) => `Min length: ${error.requiredLength}`
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ]
|
|
23
72
|
*/
|
|
24
73
|
const VALIDATION_MESSAGES = new InjectionToken('RE_VALIDATION_MESSAGES', {
|
|
25
74
|
providedIn: 'root',
|
|
@@ -809,5 +858,5 @@ const generateId = (limit = 15, radix = 36) => Math.random()
|
|
|
809
858
|
* Generated bundle index. Do not edit.
|
|
810
859
|
*/
|
|
811
860
|
|
|
812
|
-
export { CURRENT_DEVICE, SELECTED_LANG, SELECTED_THEME, VALIDATION_MESSAGES, appendQueryParams, base64ToBlob, compareRoutes, concatArray, copyText, debounceSignal, deepEqual, downloadByBlob, downloadByUrl, fillUrlWithParams, formatDate, formatToLocaledDate, formatToSpacedNumber, generateId, getAvailableHeight, getChainedValue, getCorrectedPosition, isDatePeriod, isNullable, isNumber, isObject, makeQuery, materializeRoutePath, normalizeUrl, parseQueryArray, parseQueryParams, parseToDate, parseToDatePeriod, reformatDateToISO, throttleSignal, toDate, truncate };
|
|
861
|
+
export { CHANGE_LANG, CHANGE_THEME, CURRENT_DEVICE, SELECTED_LANG, SELECTED_THEME, TRANSLATION, VALIDATION_MESSAGES, appendQueryParams, base64ToBlob, compareRoutes, concatArray, copyText, debounceSignal, deepEqual, downloadByBlob, downloadByUrl, fillUrlWithParams, formatDate, formatToLocaledDate, formatToSpacedNumber, generateId, getAvailableHeight, getChainedValue, getCorrectedPosition, isDatePeriod, isNullable, isNumber, isObject, makeQuery, materializeRoutePath, normalizeUrl, parseQueryArray, parseQueryParams, parseToDate, parseToDatePeriod, reformatDateToISO, throttleSignal, toDate, truncate };
|
|
813
862
|
//# sourceMappingURL=reforgium-internal.mjs.map
|