@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
- ## 🎯 Purpose
16
+ ## Why
17
17
 
18
18
  - Centralize shared domain primitives
19
- - Avoid cross-package circular dependencies
20
- - Keep feature and UI layers clean
19
+ - Prevent cross-package circular dependencies
20
+ - Keep feature/UI layers clean
21
21
  - Enable aggressive tree-shaking and dead-code elimination
22
- - Serve as a reusable internal base across multiple libraries and apps
22
+ - Provide a reusable internal base across multiple libraries and apps
23
23
 
24
24
  ---
25
25
 
26
- ## 🚀 What’s Inside
26
+ ## What’s inside
27
27
 
28
- ### 📦 Core Modules
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
- - **[Models](src/models/README.md)**
31
- Shared domain models, interfaces, and value objects.
32
+ > It’s the bedrock, not the building.
32
33
 
33
- - **[Tokens](src/tokens/README.md)**
34
- Typed DI tokens for configuration, environment, and infrastructure contracts.
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
- - **[Utilities](src/utils/README.md)**
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
- It’s the **bedrock**, not the building.
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
- ## 📦 Installation
150
+ ## Tokens
151
+ The localization system is built around a service that manages translations across different languages and namespaces. It supports:
45
152
 
46
- ```bash
47
- npm install @reforgium/internal
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
- * Текущий язык приложения как Signal.
5
- * Можно переопределить в app.config своим провайдером.
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
- * Текущий язык приложения как Signal.
11
- * Можно переопределить в app.config своим провайдером.
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
- * Текущий язык приложения как Signal.
17
- * Можно переопределить в app.config своим провайдером.
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
- * Токен карты сообщений валидации (переопределяй в feature-модуле).
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