@ryuzaki13/react-foundation-lib 1.3.1 → 1.4.1

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.
Files changed (38) hide show
  1. package/README.md +20 -16
  2. package/dist/table/index.d.ts +1 -0
  3. package/dist/table/index.d.ts.map +1 -1
  4. package/dist/table/index.js +77 -64
  5. package/dist/table/index.js.map +1 -1
  6. package/dist/table/tanStackFeatures.d.ts +19 -0
  7. package/dist/table/tanStackFeatures.d.ts.map +1 -0
  8. package/dist/table/types.d.ts +17 -2
  9. package/dist/table/types.d.ts.map +1 -1
  10. package/package.json +9 -9
  11. package/src/array/README.mdx +1630 -0
  12. package/src/binary/README.mdx +1405 -0
  13. package/src/copy/README.mdx +992 -0
  14. package/src/crypto/README.mdx +1052 -0
  15. package/src/dom/README.mdx +2179 -0
  16. package/src/file/README.mdx +1957 -0
  17. package/src/formatters/README.mdx +469 -0
  18. package/src/formatters/boolean/README.mdx +494 -0
  19. package/src/formatters/date/README.mdx +732 -0
  20. package/src/formatters/number/README.mdx +542 -0
  21. package/src/formatters/pipeline/README.mdx +629 -0
  22. package/src/formatters/rowBased/README.mdx +486 -0
  23. package/src/formatters/strings/README.mdx +442 -0
  24. package/src/formatters/valueState/README.mdx +459 -0
  25. package/src/formulas/README.mdx +1283 -0
  26. package/src/binary/README.md +0 -110
  27. package/src/docs/browserAndReact.mdx +0 -150
  28. package/src/docs/filesAndExcel.mdx +0 -163
  29. package/src/docs/formatters-runtime.mdx +0 -455
  30. package/src/docs/formatters.mdx +0 -380
  31. package/src/docs/odataAndTables.mdx +0 -178
  32. package/src/docs/pureUtilities.mdx +0 -96
  33. package/src/docs/runtimeAndState.mdx +0 -155
  34. package/src/file/README.md +0 -289
  35. package/src/formatters/date/README.md +0 -520
  36. package/src/formatters/number/README.md +0 -123
  37. package/src/formatters/valueState/README.md +0 -275
  38. package/src/formulas/README.md +0 -42
@@ -0,0 +1,442 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Foundation Lib/API/Formatters/Strings" />
4
+
5
+ # Строковые форматтеры
6
+
7
+ Модуль содержит небольшие предсказуемые функции для подготовки пользовательского текста: обрезки пробелов, безопасного преобразования в строку, удаления ведущих нулей, сокращения длинного текста и выбора русской формы слова.
8
+
9
+ Все функции экспортируются через один публичный entrypoint:
10
+
11
+ ```ts
12
+ import {
13
+ formatRussianPlural,
14
+ normalizeRequiredText,
15
+ normalizeText,
16
+ normalizeTextSpaces,
17
+ normalizeTextToLower,
18
+ normalizeTextWithFallback,
19
+ selectRussianPluralForm,
20
+ startsWithIgnoringZeros,
21
+ stripInnerSpaces,
22
+ stripLeadingZeros,
23
+ toSafeString,
24
+ truncateText
25
+ } from "@ryuzaki13/react-foundation-lib/formatters";
26
+ ```
27
+
28
+ Импорта `@ryuzaki13/react-foundation-lib/formatters/strings` нет: каталог `strings` — внутренняя организация исходников, а не отдельный package subpath.
29
+
30
+ ## Быстрый выбор функции
31
+
32
+ | Задача | Функция | Пример результата |
33
+ | ------------------------------------------- | --------------------------- | ------------------------------------------ |
34
+ | Получить непустой текст или `undefined` | `normalizeText` | `" Иван "` → `"Иван"` |
35
+ | Получить текст с fallback | `normalizeTextWithFallback` | `null` → заданный fallback |
36
+ | Получить обязательную строку | `normalizeRequiredText` | `null` → `""` |
37
+ | Нормализовать и привести к нижнему регистру | `normalizeTextToLower` | `" Admin "` → `"admin"` |
38
+ | Безопасно выполнить `String(value)` | `toSafeString` | `null` → `""`, `42` → `"42"` |
39
+ | Схлопнуть разные пробелы | `normalizeTextSpaces` | `" Иван\u00a0 Иванов "` → `"Иван Иванов"` |
40
+ | Удалить пробелы из значения | `stripInnerSpaces` | `"1 234\u00a0567"` → `"1234567"` |
41
+ | Удалить ведущие нули у целого числа | `stripLeadingZeros` | `"-00042"` → `"-42"` |
42
+ | Сравнить начало без ведущих нулей | `startsWithIgnoringZeros` | `("000123", "12")` → `true` |
43
+ | Обрезать длинный текст | `truncateText` | `("abcdef", 3)` → `"abc..."` |
44
+ | Выбрать русскую форму слова | `selectRussianPluralForm` | `22` → форма `few` |
45
+ | Получить число вместе со словом | `formatRussianPlural` | `22` → `"22 файла"` |
46
+
47
+ ## Базовые понятия для начинающих
48
+
49
+ ### `unknown` не означает строку
50
+
51
+ Значение типа `unknown` может оказаться строкой, числом, объектом, `null` или чем угодно ещё. Функции этого модуля обрабатывают такие значения по-разному:
52
+
53
+ - `normalizeText*` считают текстом только настоящее значение типа `string`;
54
+ - `toSafeString` преобразует почти любое значение через встроенную функцию `String`;
55
+ - `stripLeadingZeros` предназначена для строки, которая изображает целое число.
56
+
57
+ Не подменяйте одну операцию другой. Например, `normalizeText(42)` вернёт `undefined`, а `toSafeString(42)` — строку `"42"`.
58
+
59
+ ### `undefined`, `null` и пустая строка различаются
60
+
61
+ - `undefined` обычно означает «значение не задано»;
62
+ - `null` обычно означает «значение явно отсутствует»;
63
+ - `""` — строка, но в ней нет символов;
64
+ - `" "` — непустая строка на уровне JavaScript, однако после `trim()` она становится пустой.
65
+
66
+ `normalizeText` объединяет эти случаи в удобный результат: содержательная строка либо `undefined`.
67
+
68
+ ## Нормализация текста
69
+
70
+ ### `normalizeText(value)`
71
+
72
+ ```ts
73
+ function normalizeText(value: unknown): string | undefined;
74
+ ```
75
+
76
+ Функция:
77
+
78
+ 1. проверяет, что значение является строкой;
79
+ 2. удаляет пробелы в начале и конце через `trim()`;
80
+ 3. возвращает `undefined`, если после этого строка пуста.
81
+
82
+ ```ts
83
+ normalizeText(" документ "); // "документ"
84
+ normalizeText(""); // undefined
85
+ normalizeText(" "); // undefined
86
+ normalizeText(null); // undefined
87
+ normalizeText(100); // undefined
88
+ ```
89
+
90
+ Она не схлопывает пробелы внутри строки и не меняет регистр:
91
+
92
+ ```ts
93
+ normalizeText(" Иван Иванов "); // "Иван Иванов"
94
+ ```
95
+
96
+ Типичный сценарий — подготовка необязательного поля перед сохранением:
97
+
98
+ ```ts
99
+ const description = normalizeText(form.description);
100
+
101
+ // description имеет тип string | undefined
102
+ ```
103
+
104
+ ### `normalizeTextWithFallback(value, fallback?)`
105
+
106
+ ```ts
107
+ function normalizeTextWithFallback(value: unknown, fallback?: string): string;
108
+ ```
109
+
110
+ Возвращает результат `normalizeText(value)`. Если содержательного текста нет, возвращает `fallback`. По умолчанию fallback равен пустой строке.
111
+
112
+ ```ts
113
+ normalizeTextWithFallback(" Готово "); // "Готово"
114
+ normalizeTextWithFallback(null); // ""
115
+ normalizeTextWithFallback(" ", "Не указано"); // "Не указано"
116
+ ```
117
+
118
+ Важно: fallback возвращается буквально. Функция не обрезает и не проверяет сам fallback.
119
+
120
+ ### `normalizeRequiredText(value)`
121
+
122
+ ```ts
123
+ function normalizeRequiredText(value: unknown): string;
124
+ ```
125
+
126
+ Это короткая форма `normalizeTextWithFallback(value, "")`:
127
+
128
+ ```ts
129
+ normalizeRequiredText(" Отчёт "); // "Отчёт"
130
+ normalizeRequiredText(undefined); // ""
131
+ normalizeRequiredText(42); // ""
132
+ ```
133
+
134
+ Используйте её там, где вызывающему коду всегда нужна строка. Название `Required` не выполняет валидацию обязательности: пустой ввод всё равно превращается в `""`.
135
+
136
+ ### `normalizeTextToLower(value)`
137
+
138
+ ```ts
139
+ function normalizeTextToLower(value: unknown): string;
140
+ ```
141
+
142
+ Обрезает внешние пробелы, затем вызывает `toLowerCase()`. Если вход не является содержательной строкой, возвращает `""`.
143
+
144
+ ```ts
145
+ normalizeTextToLower(" AdMiN "); // "admin"
146
+ normalizeTextToLower(null); // ""
147
+ ```
148
+
149
+ Функция использует обычный `toLowerCase`, а не locale-aware `toLocaleLowerCase`. Для большинства технических ключей это ожидаемое поведение.
150
+
151
+ ### `toSafeString(value)`
152
+
153
+ ```ts
154
+ function toSafeString(value: unknown): string;
155
+ ```
156
+
157
+ `null` и `undefined` становятся пустой строкой. Остальные значения передаются встроенной функции `String`.
158
+
159
+ ```ts
160
+ toSafeString(null); // ""
161
+ toSafeString(undefined); // ""
162
+ toSafeString(42); // "42"
163
+ toSafeString(false); // "false"
164
+ toSafeString([1, 2]); // "1,2"
165
+ toSafeString({ id: 1 }); // "[object Object]"
166
+ ```
167
+
168
+ Последние два примера показывают ограничение: функция гарантирует строковый тип, но не создаёт красивое представление сложных объектов. Для объектов нужен осмысленный formatter или сериализатор.
169
+
170
+ ### `normalizeTextSpaces(value)`
171
+
172
+ ```ts
173
+ function normalizeTextSpaces(value: unknown): string;
174
+ ```
175
+
176
+ Функция сначала применяет семантику `normalizeRequiredText`, затем заменяет любую последовательность следующих пробельных символов одним обычным пробелом:
177
+
178
+ - стандартные пробельные символы JavaScript (`\s`), включая табуляцию и перенос строки;
179
+ - неразрывный пробел `U+00A0`;
180
+ - узкий неразрывный пробел `U+202F`.
181
+
182
+ ```ts
183
+ normalizeTextSpaces(" Иван\t\nИванов "); // "Иван Иванов"
184
+ normalizeTextSpaces("1\u00a0234\u202f567"); // "1 234 567"
185
+ normalizeTextSpaces(123); // ""
186
+ ```
187
+
188
+ Используйте функцию для обычного пользовательского текста. Для машинных идентификаторов схлопывание пробелов может менять смысл значения.
189
+
190
+ ## Удаление пробелов и ведущих нулей
191
+
192
+ ### `stripInnerSpaces(value)`
193
+
194
+ ```ts
195
+ function stripInnerSpaces(value: string): string;
196
+ ```
197
+
198
+ Удаляет из всей строки:
199
+
200
+ - обычный пробел;
201
+ - неразрывный пробел `U+00A0`;
202
+ - узкий неразрывный пробел `U+202F`.
203
+
204
+ ```ts
205
+ stripInnerSpaces("1 234 567"); // "1234567"
206
+ stripInnerSpaces("1\u00a0234\u202f567"); // "1234567"
207
+ ```
208
+
209
+ Несмотря на слово `Inner` в имени, удаляются все перечисленные пробелы, в том числе в начале и конце. Табуляция и перевод строки не удаляются:
210
+
211
+ ```ts
212
+ stripInnerSpaces("\t1 2\n"); // "\t12\n"
213
+ ```
214
+
215
+ ### `stripLeadingZeros(value)`
216
+
217
+ ```ts
218
+ function stripLeadingZeros(value: string): string;
219
+ ```
220
+
221
+ Функция предназначена для строкового представления целого числа:
222
+
223
+ 1. обрезает внешние пробелы;
224
+ 2. проверяет формат `необязательный минус + цифры`;
225
+ 3. удаляет лишние нули в начале цифровой части;
226
+ 4. оставляет один ноль, если число состояло только из нулей.
227
+
228
+ ```ts
229
+ stripLeadingZeros("00042"); // "42"
230
+ stripLeadingZeros("-00042"); // "-42"
231
+ stripLeadingZeros("0000"); // "0"
232
+ stripLeadingZeros("-0000"); // "-0"
233
+ stripLeadingZeros(" "); // "0"
234
+ ```
235
+
236
+ Если строка не похожа на целое число, она возвращается только с обрезанными внешними пробелами:
237
+
238
+ ```ts
239
+ stripLeadingZeros("+00042"); // "+00042"
240
+ stripLeadingZeros("001.50"); // "001.50"
241
+ stripLeadingZeros("000A12"); // "000A12"
242
+ ```
243
+
244
+ Не используйте эту функцию для дробей, артикулов или кодов, где ведущие нули значимы.
245
+
246
+ ### `startsWithIgnoringZeros(value, searchText)`
247
+
248
+ ```ts
249
+ function startsWithIgnoringZeros(value: string, searchText: string): boolean;
250
+ ```
251
+
252
+ Обе строки приводятся к нижнему регистру, из их начала удаляются все нули, затем выполняется обычный `startsWith`.
253
+
254
+ ```ts
255
+ startsWithIgnoringZeros("000ABC123", "abc"); // true
256
+ startsWithIgnoringZeros("00012345", "0012"); // true
257
+ startsWithIgnoringZeros("00123", "24"); // false
258
+ ```
259
+
260
+ Функция не вызывает `trim()`:
261
+
262
+ ```ts
263
+ startsWithIgnoringZeros(" 00123", "123"); // false
264
+ ```
265
+
266
+ Если искомая строка состоит только из нулей, после удаления нулей получается `""`. Любая строка начинается с пустой строки, поэтому результат будет `true`:
267
+
268
+ ```ts
269
+ startsWithIgnoringZeros("ABC", "000"); // true
270
+ ```
271
+
272
+ Если такое поведение не подходит поисковому интерфейсу, заранее проверяйте нормализованный поисковый запрос.
273
+
274
+ ## Обрезка длинного текста
275
+
276
+ ### `truncateText(value, maxLength)`
277
+
278
+ ```ts
279
+ function truncateText(value: unknown, maxLength: number): string | undefined;
280
+ ```
281
+
282
+ Сначала применяется `normalizeText`. Если строка длиннее `maxLength`, берутся первые `maxLength` кодовых единиц и добавляется `...`.
283
+
284
+ ```ts
285
+ truncateText(" abcdef ", 3); // "abc..."
286
+ truncateText("abc", 3); // "abc"
287
+ truncateText(" ", 10); // undefined
288
+ truncateText(123, 10); // undefined
289
+ ```
290
+
291
+ `maxLength` ограничивает только исходную часть. Три точки добавляются сверху, поэтому длина результата может быть `maxLength + 3`.
292
+
293
+ Передавайте целое неотрицательное число. Функция не валидирует параметр. Кроме того, JavaScript `slice` считает UTF-16 code units, поэтому граница может разрезать emoji или сложный Unicode-символ. Для строгого UI-ограничения по визуальным символам нужен отдельный Unicode-aware механизм.
294
+
295
+ ## Русские формы множественного числа
296
+
297
+ ### Модель `one`, `few`, `many`, `other`
298
+
299
+ Русский язык использует разные формы слова:
300
+
301
+ - `one`: `1 файл`, `21 файл`;
302
+ - `few`: `2 файла`, `24 файла`;
303
+ - `many`: `5 файлов`, `11 файлов`, `100 файлов`;
304
+ - `other`: обычно дробные значения, например `1.5 файла`.
305
+
306
+ Модуль использует `Intl.PluralRules("ru-RU")`, поэтому не нужно самостоятельно писать правила с остатками от деления.
307
+
308
+ ```ts
309
+ type RussianPluralForms = {
310
+ one: string;
311
+ few: string;
312
+ many: string;
313
+ other?: string;
314
+ };
315
+ ```
316
+
317
+ Поле `other` необязательно. Если оно не задано, для категории `other` используется форма `few`.
318
+
319
+ ### `selectRussianPluralForm(value, forms)`
320
+
321
+ ```ts
322
+ function selectRussianPluralForm(value: number, forms: RussianPluralForms): string;
323
+ ```
324
+
325
+ ```ts
326
+ const fileForms = {
327
+ one: "файл",
328
+ few: "файла",
329
+ many: "файлов",
330
+ other: "файла"
331
+ };
332
+
333
+ selectRussianPluralForm(1, fileForms); // "файл"
334
+ selectRussianPluralForm(2, fileForms); // "файла"
335
+ selectRussianPluralForm(5, fileForms); // "файлов"
336
+ selectRussianPluralForm(1.5, fileForms); // "файла"
337
+ ```
338
+
339
+ Для `NaN`, `Infinity` и `-Infinity` функция выбрасывает `RangeError`, потому что выбрать грамматическую форму для нечислового количества нельзя.
340
+
341
+ ### `formatRussianPlural(value, forms)`
342
+
343
+ ```ts
344
+ function formatRussianPlural(value: number, forms: RussianPluralForms): string;
345
+ ```
346
+
347
+ Добавляет число перед выбранной формой через пробел:
348
+
349
+ ```ts
350
+ formatRussianPlural(1, fileForms); // "1 файл"
351
+ formatRussianPlural(22, fileForms); // "22 файла"
352
+ formatRussianPlural(100, fileForms); // "100 файлов"
353
+ ```
354
+
355
+ Само число вставляется через обычное строковое преобразование JavaScript. Локализованное форматирование числа не выполняется:
356
+
357
+ ```ts
358
+ formatRussianPlural(1.5, fileForms); // "1.5 файла", не "1,5 файла"
359
+ ```
360
+
361
+ Если нужно локализовать число, объедините `selectRussianPluralForm` с числовым форматтером:
362
+
363
+ ```ts
364
+ import { formatNumber, selectRussianPluralForm } from "@ryuzaki13/react-foundation-lib/formatters";
365
+
366
+ const count = 1234.5;
367
+ const label = `${formatNumber(count, "decimal")} ${selectRussianPluralForm(count, fileForms)}`;
368
+ ```
369
+
370
+ ## Практический пример: нормализация формы
371
+
372
+ ```ts
373
+ import { normalizeText, normalizeTextSpaces, normalizeTextToLower, stripLeadingZeros } from "@ryuzaki13/react-foundation-lib/formatters";
374
+
375
+ const draft = {
376
+ name: " Иван Иванов ",
377
+ login: " IVANOV ",
378
+ comment: " ",
379
+ sequence: "00042"
380
+ };
381
+
382
+ const snapshot = {
383
+ name: normalizeTextSpaces(draft.name), // "Иван Иванов"
384
+ login: normalizeTextToLower(draft.login), // "ivanov"
385
+ comment: normalizeText(draft.comment), // undefined
386
+ sequence: stripLeadingZeros(draft.sequence) // "42"
387
+ };
388
+ ```
389
+
390
+ Такая нормализация подходит для явно выбранной границы сохранения. Не применяйте её автоматически на каждом нажатии клавиши: пользовательский draft обычно должен сохранять введённый текст буквально до сохранения.
391
+
392
+ ## Частые ошибки
393
+
394
+ ### Использовать `toSafeString` как универсальный formatter
395
+
396
+ `toSafeString({ id: 1 })` возвращает `"[object Object]"`. Функция защищает от `null` и `undefined`, но не знает, как должен выглядеть доменный объект.
397
+
398
+ ### Ожидать, что `stripInnerSpaces` удалит все whitespace
399
+
400
+ Она удаляет только три конкретных вида пробела. Для схлопывания табуляций и переносов строки используйте `normalizeTextSpaces`.
401
+
402
+ ### Удалять нули у идентификаторов
403
+
404
+ Коды `"000123"` и `"123"` могут быть разными бизнес-идентификаторами. `stripLeadingZeros` меняет значение и должна применяться только там, где строка действительно означает целое число.
405
+
406
+ ### Считать, что `truncateText` возвращает строку заданной длины
407
+
408
+ Три точки не входят в `maxLength`. При `maxLength = 10` итоговая строка может содержать 13 кодовых единиц.
409
+
410
+ ### Передавать строку в plural API
411
+
412
+ ```ts
413
+ // Неправильно: функция ожидает number.
414
+ // formatRussianPlural("5", fileForms);
415
+
416
+ formatRussianPlural(Number("5"), fileForms);
417
+ ```
418
+
419
+ Перед преобразованием внешней строки убедитесь, что получилось конечное число.
420
+
421
+ ## Краткая API-справка
422
+
423
+ | API | Вход | Результат | Может выбросить ошибку |
424
+ | --------------------------- | -------------------- | --------------------- | ------------------------------------------------------ |
425
+ | `normalizeText` | `unknown` | `string \| undefined` | нет |
426
+ | `normalizeTextWithFallback` | `unknown`, `string?` | `string` | нет |
427
+ | `normalizeRequiredText` | `unknown` | `string` | нет |
428
+ | `normalizeTextToLower` | `unknown` | `string` | нет |
429
+ | `toSafeString` | `unknown` | `string` | теоретически `String(value)` для экзотического объекта |
430
+ | `normalizeTextSpaces` | `unknown` | `string` | нет |
431
+ | `stripInnerSpaces` | `string` | `string` | нет для корректного типа |
432
+ | `stripLeadingZeros` | `string` | `string` | нет для корректного типа |
433
+ | `startsWithIgnoringZeros` | `string`, `string` | `boolean` | нет для корректных типов |
434
+ | `truncateText` | `unknown`, `number` | `string \| undefined` | нет при обычных значениях |
435
+ | `selectRussianPluralForm` | `number`, формы | `string` | `RangeError` для не-конечного числа |
436
+ | `formatRussianPlural` | `number`, формы | `string` | `RangeError` для не-конечного числа |
437
+
438
+ ## Связанная документация
439
+
440
+ - [Обзор всего модуля `formatters`](../README.mdx)
441
+ - [Числа и числовые строки](../number/README.mdx)
442
+ - [Форматтеры boolean и ABAP-флагов](../boolean/README.mdx)