@foxford/foxford-utils 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/index.d.cts ADDED
@@ -0,0 +1,516 @@
1
+ import qs from 'query-string';
2
+
3
+ /**
4
+ * Генерирует уникальный идентификатор (qid)
5
+ * @param length - длина уникального идентификатора
6
+ * @param number - включает ли цифры в алфавит
7
+ * @return строка
8
+ */
9
+ declare function qid(length?: number, number?: boolean): string;
10
+
11
+ /**
12
+ * Генерирует уникальный сгруппированный идентификатор (псевдо-UUID в стиле v4).
13
+ * Формат: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (hex)
14
+ */
15
+ declare function uuid(): string;
16
+
17
+ /**
18
+ * Фильтрует поля объекта
19
+ * @param obj - исходный объект
20
+ * @param filterFunc - предикат, принимающий (key, value)
21
+ * @returns новый объект с отфильтрованными полями
22
+ */
23
+ declare function pickBy<T extends Record<string, unknown>>(obj: T, filterFunc: (key: keyof T & string, value: T[keyof T]) => boolean): Partial<T>;
24
+
25
+ type ToggleEventLike = {
26
+ currentTarget: EventTarget | null;
27
+ };
28
+ declare class Collapse {
29
+ onClickHandler: (e: ToggleEventLike) => boolean;
30
+ private _onClickEventListener;
31
+ private _boundMakeCollapse;
32
+ private _collapses;
33
+ constructor();
34
+ makeCollapse(collapse: HTMLElement): boolean;
35
+ init(): void;
36
+ destroy(): void;
37
+ reinit(): void;
38
+ }
39
+
40
+ /**
41
+ * Декоратор для функции, добавляющий debounce (задержку выполнения).
42
+ *
43
+ * @export
44
+ * @param {function} f - исходная функция
45
+ * @param {number} ms - задержка в миллисекундах
46
+ * @returns {function} - функция-декоратор с debounce
47
+ */
48
+ declare function debounce<T extends (...args: any[]) => any>(f: T, ms: number): (this: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<typeof setTimeout>;
49
+
50
+ /**
51
+ * Преобразует массив элементов в объект, где ключ — строковый id элемента.
52
+ *
53
+ * Пример:
54
+ * [{ id: 1, name: 'item 1' }] -> { "1": { id: 1, name: 'item 1' } }
55
+ */
56
+ declare function indexById<T extends {
57
+ id: PropertyKey;
58
+ }>(items: readonly T[]): Record<string, T>;
59
+
60
+ /**
61
+ * Русская форма множественного числа.
62
+ * @docs http://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
63
+ * @example pluralize(1, ['штука', 'штуки', 'штук'])
64
+ */
65
+ type PluralForms<T> = readonly [T, T, T];
66
+ declare function pluralize<T>(counter: number, forms: PluralForms<T>): T;
67
+
68
+ /**
69
+ * Возвращает объект, пригодный для React-свойства `dangerouslySetInnerHTML`.
70
+ *
71
+ * @example
72
+ * <div dangerouslySetInnerHTML={rawMarkup("<b>text</b>")} />
73
+ */
74
+ type DangerousHTML = {
75
+ __html: string;
76
+ };
77
+ declare function rawMarkup(text: string): DangerousHTML;
78
+
79
+ /**
80
+ * Делает первую букву строки заглавной
81
+ * @param str - входная строка
82
+ * @returns строка с первой заглавной буквой
83
+ */
84
+ declare function capitalize(str: string): string;
85
+
86
+ type FileLike = {
87
+ size: number;
88
+ };
89
+ /**
90
+ * getFilesSize — суммирует size у переданных файлов/вложений
91
+ * Совместимо с File/Blob (у них тоже есть поле size).
92
+ */
93
+ declare function getFilesSize(attachments: ReadonlyArray<FileLike>, files: ReadonlyArray<FileLike>): number;
94
+
95
+ type MimeEntry = {
96
+ mime: string
97
+ extensions: string[]
98
+ }
99
+
100
+ type MimeFiles = ReadonlyArray<MimeEntry>;
101
+ /**
102
+ * Возвращает массив MIME-типов из массива файлов
103
+ */
104
+ declare function getMimeTypes(files: MimeFiles): string[];
105
+
106
+ /**
107
+ * Возвращает случайное целое число между min (включительно) и max (не включая max)
108
+ */
109
+ declare function getRandomInt(min: number, max: number): number;
110
+
111
+ type HasGroupId = {
112
+ group: {
113
+ id: string | number;
114
+ };
115
+ };
116
+ /**
117
+ * Превращает массив элементов с group.id в объект,
118
+ * где ключ — String(group.id), значение — сам элемент.
119
+ *
120
+ * Последний элемент с одинаковым group.id перезапишет предыдущий.
121
+ */
122
+ declare function indexByGroupId<T extends HasGroupId>(items: ReadonlyArray<T>): Record<string, T>;
123
+
124
+ /**
125
+ * Прокручивает окно к верхней границе первого элемента, соответствующего селектору.
126
+ * Возвращает `false`, если элемент не найден; иначе возвращает `undefined`.
127
+ */
128
+ declare function scrollToElement(selector: string): false | undefined;
129
+
130
+ declare const TYPES: {
131
+ readonly days: readonly ["день", "дня", "дней"];
132
+ readonly exercises: readonly ["занятие", "занятия", "занятий"];
133
+ readonly hours: readonly ["час", "часа", "часов"];
134
+ readonly members: readonly ["участник", "участника", "участников"];
135
+ readonly minutes: readonly ["минута", "минуты", "минут"];
136
+ readonly points: readonly ["балл", "балла", "баллов"];
137
+ readonly remains: readonly ["остался", "осталось", "осталось"];
138
+ readonly seconds: readonly ["секунда", "секунды", "секунд"];
139
+ readonly students: readonly ["ученик", "ученика", "учеников"];
140
+ readonly studentsParentalCase: readonly ["ученика", "учеников", "учеников"];
141
+ readonly tasks: readonly ["задача", "задачи", "задач"];
142
+ };
143
+ type PluralizeType = keyof typeof TYPES;
144
+ /**
145
+ * Возвращает строку во множественном числе для заданного типа
146
+ *
147
+ * @param counter — число, по которому выбирается форма
148
+ * @param type — один из предопределённых ключей типов
149
+ */
150
+ declare function pluralizeByType(counter: number, type: PluralizeType): string;
151
+
152
+ /**
153
+ * Конвертирует строку base64 в ArrayBuffer.
154
+ */
155
+ declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
156
+
157
+ /**
158
+ * Парсит строку-список вида:
159
+ * "— Преподаватель кафедры ... <br>
160
+ * — Старший преподаватель ..."
161
+ * в массив элементов без начальных тире/дефисов и пробелов.
162
+ *
163
+ * Поддерживаемые разделители между пунктами:
164
+ * - начало строки
165
+ * - <br>, <br/>, <br /> (в любом регистре)
166
+ * - перевод строки \n
167
+ *
168
+ * Поддерживаемые маркеры пункта:
169
+ * - дефис '-' и множество вариантов тире:
170
+ * U+2010..U+2015, U+FE58, U+FE63, U+FF0D
171
+ */
172
+ declare function parseStringListToArray(input?: string): string[];
173
+
174
+ interface SourceOption {
175
+ id: string | number;
176
+ name: string;
177
+ image_url?: string | null;
178
+ }
179
+ interface SelectOption {
180
+ value: string | number;
181
+ label: string;
182
+ image_url?: string | null;
183
+ }
184
+ /**
185
+ * Преобразует массив опций (например, уровней/классов) в формат для select.
186
+ * @example
187
+ * transformOptionsForSelect([{ id: 1, name: 'A', image_url: 'x.png' }])
188
+ * // => [{ value: 1, label: 'A', image_url: 'x.png' }]
189
+ */
190
+ declare const transformOptionsForSelect: <T extends SourceOption>(options?: readonly T[]) => SelectOption[];
191
+
192
+ type AnyRecord = Record<string | number | symbol, unknown>;
193
+ /**
194
+ * Глубокий мерж объектов «как в оригинале»:
195
+ * - мутирует **target** и не мутирует **source**
196
+ * - если по ключу и в target, и в source лежат объекты — сливаем рекурсивно
197
+ * - иначе просто присваиваем ссылку из source в target
198
+ */
199
+ declare function merge<T extends AnyRecord, S extends AnyRecord>(target: T, source: S): T & S;
200
+
201
+ /**
202
+ * Определяет Internet Explorer (<=11) или старый Edge (движок EdgeHTML).
203
+ * @returns false, если это не IE/EdgeHTML; иначе — номер основной версии.
204
+ */
205
+ declare function detectIE(ua?: string): number | false;
206
+
207
+ type SerializedField = {
208
+ name: string;
209
+ value: string;
210
+ };
211
+ /**
212
+ * Сериализует поля формы аналогично jQuery.serializeArray()
213
+ */
214
+ declare function serializeArray(form: unknown): SerializedField[];
215
+ /**
216
+ * Возвращает внешнюю высоту элемента (offsetHeight + вертикальные отступы).
217
+ */
218
+ declare function outerHeight(el: HTMLElement): number;
219
+ /**
220
+ * Проверяет, полностью ли элемент находится в текущей области видимости (viewport).
221
+ */
222
+ declare function isElementInViewport(el: Element): boolean;
223
+
224
+ type StringMap = Record<string, string>;
225
+ /**
226
+ * Преобразует ключи объекта в camelCase
227
+ */
228
+ declare function toCamelCase(obj: StringMap): StringMap;
229
+ /**
230
+ * Преобразует ключи объекта из camelCase в under_scored
231
+ */
232
+ declare function toUnderscoredCase(obj: StringMap): StringMap;
233
+
234
+ /**
235
+ * Разбивает массив на чанки (подмассивы) указанного размера.
236
+ *
237
+ * @param limit - Максимальный размер каждого чанка
238
+ * @param arr - Исходный массив
239
+ * @returns Массив чанков
240
+ */
241
+ declare function splitEvery<T>(limit?: number, arr?: T[]): T[][];
242
+ /**
243
+ * Удаляет дубликаты элементов из массива.
244
+ *
245
+ * @param arrArg - Массив для дедупликации
246
+ * @returns Новый массив без дубликатов
247
+ */
248
+ declare function uniq<T>(arrArg: T[]): T[];
249
+ /**
250
+ * Удаляет элемент массива по индексу.
251
+ *
252
+ * @param arr - Исходный массив
253
+ * @param index - Индекс удаляемого элемента
254
+ * @returns Новый массив без этого элемента
255
+ */
256
+ declare function removeElFromArr<T>(arr: T[], index: number): T[];
257
+ /**
258
+ * Сливает два массива объектов по общему ключу.
259
+ *
260
+ * Если объект с тем же значением ключа есть в обоих массивах,
261
+ * объекты объединяются, при этом свойства из `arr2` имеют приоритет.
262
+ *
263
+ * @param arr1 - Первый массив объектов
264
+ * @param arr2 - Второй массив объектов
265
+ * @param key - Ключевое поле для сравнения (по умолчанию: 'id')
266
+ * @returns Объединённый массив
267
+ */
268
+ declare function mergeByKey<T extends Record<string, unknown>, K extends keyof T = 'id' extends keyof T ? 'id' : keyof T>(arr1?: T[], arr2?: T[], key?: K): T[];
269
+
270
+ /**
271
+ * Функция принимает Ф.И.О, возвращает Ф.И.
272
+ *
273
+ * Примеры:
274
+ * - "Иванов Иван Иванович" -> "Иван Иванов"
275
+ * - "Иванов Иван" -> "Иван Иванов"
276
+ * - "Иванов" -> "Иванов"
277
+ */
278
+ declare const makeShortNameFromFull: (fullName?: string) => string;
279
+ /**
280
+ * Извлекает все цифры из строки
281
+ *
282
+ * Если вход не строка — вернёт пустую строку.
283
+ */
284
+ declare const extractDigits: (input?: unknown) => string;
285
+
286
+ /** Карта ISO-кодов -> символ валюты. */
287
+ declare const CURRENCY_DIRECTORY: {
288
+ readonly AFN: "؋";
289
+ readonly ALL: "Lek";
290
+ readonly ANG: "ƒ";
291
+ readonly ARS: "$";
292
+ readonly AUD: "$";
293
+ readonly AWG: "ƒ";
294
+ readonly AZN: "₼";
295
+ readonly BAM: "KM";
296
+ readonly BBD: "$";
297
+ readonly BGN: "лв";
298
+ readonly BMD: "$";
299
+ readonly BND: "$";
300
+ readonly BOB: "$b";
301
+ readonly BRL: "R$";
302
+ readonly BSD: "$";
303
+ readonly BWP: "P";
304
+ readonly BYR: "Br";
305
+ readonly BZD: "BZ$";
306
+ readonly CAD: "C$";
307
+ readonly CHF: "CHF";
308
+ readonly CLP: "$";
309
+ readonly CNY: "¥";
310
+ readonly COP: "$";
311
+ readonly CRC: "₡";
312
+ readonly CUP: "₱";
313
+ readonly CZK: "Kč";
314
+ readonly DKK: "kr";
315
+ readonly DOP: "RD$";
316
+ readonly EEK: "kr";
317
+ readonly EGP: "£";
318
+ readonly EUR: "€";
319
+ readonly FJD: "$";
320
+ readonly FKP: "£";
321
+ readonly FRF: "₣";
322
+ readonly GBP: "£";
323
+ readonly GGP: "£";
324
+ readonly GHC: "¢";
325
+ readonly GIP: "£";
326
+ readonly GTQ: "Q";
327
+ readonly GYD: "$";
328
+ readonly HKD: "$";
329
+ readonly HNL: "L";
330
+ readonly HRK: "kn";
331
+ readonly HUF: "Ft";
332
+ readonly IDR: "Rp";
333
+ readonly ILS: "₪";
334
+ readonly IMP: "£";
335
+ readonly INR: "₨";
336
+ readonly IRR: "﷼";
337
+ readonly ISK: "kr";
338
+ readonly JEP: "£";
339
+ readonly JMD: "J$";
340
+ readonly JPY: "¥";
341
+ readonly KGS: "KGS";
342
+ readonly KHR: "៛";
343
+ readonly KPW: "₩";
344
+ readonly KRW: "₩";
345
+ readonly KYD: "$";
346
+ readonly KZT: "₸";
347
+ readonly LAK: "₭";
348
+ readonly LBP: "£";
349
+ readonly LKR: "₨";
350
+ readonly LRD: "$";
351
+ readonly LTL: "Lt";
352
+ readonly LVL: "Ls";
353
+ readonly MKD: "ден";
354
+ readonly MNT: "₮";
355
+ readonly MUR: "₨";
356
+ readonly MXN: "$";
357
+ readonly MYR: "RM";
358
+ readonly MZN: "MT";
359
+ readonly NAD: "$";
360
+ readonly NGN: "₦";
361
+ readonly NIO: "C$";
362
+ readonly NOK: "kr";
363
+ readonly NPR: "₨";
364
+ readonly NZD: "$";
365
+ readonly OMR: "﷼";
366
+ readonly PAB: "B/.";
367
+ readonly PEN: "S/.";
368
+ readonly PHP: "₱";
369
+ readonly PKR: "₨";
370
+ readonly PLN: "zł";
371
+ readonly PYG: "Gs";
372
+ readonly QAR: "﷼";
373
+ readonly RON: "lei";
374
+ readonly RSD: "Дин.";
375
+ readonly RUR: "₽";
376
+ readonly SAR: "﷼";
377
+ readonly SBD: "$";
378
+ readonly SCR: "₨";
379
+ readonly SEK: "kr";
380
+ readonly SGD: "$";
381
+ readonly SHP: "£";
382
+ readonly SOS: "S";
383
+ readonly SRD: "$";
384
+ readonly SVC: "$";
385
+ readonly SYP: "£";
386
+ readonly THB: "฿";
387
+ readonly TRL: "₤";
388
+ readonly TRY: "₤";
389
+ readonly TTD: "TT$";
390
+ readonly TVD: "$";
391
+ readonly TWD: "NT$";
392
+ readonly UAH: "₴";
393
+ readonly USD: "$";
394
+ readonly UYU: "$U";
395
+ readonly UZS: "лв";
396
+ readonly VEF: "Bs";
397
+ readonly VND: "₫";
398
+ readonly XCD: "$";
399
+ readonly YER: "﷼";
400
+ readonly ZAR: "R";
401
+ readonly ZWD: "Z$";
402
+ };
403
+ /**
404
+ * Возвращает символ валюты по ISO-коду.
405
+ *
406
+ * Если код неизвестен — вернёт сам переданный код без изменений.
407
+ */
408
+ declare function getCurrencySymbol(currencyCode: string): string;
409
+
410
+ /**
411
+ * Регулирует яркость (осветляет/затемняет) шестнадцатеричного цвета.
412
+ * Принимает 3- или 6-символьный hex (с решёткой '#' или без неё).
413
+ */
414
+ declare function colorLuminance(rawHex: string, lum?: number): string;
415
+ /**
416
+ * Собирает linear-gradient, используя чуть более светлый и тёмный оттенки цвета.
417
+ * @param degree CSS-угол, например "90deg"
418
+ * @param color hex-строка БЕЗ '#', например "6699cc"
419
+ */
420
+ declare function getGradient(degree: string, color: string): string;
421
+ /**
422
+ * Детерминированный выбор цвета по строке.
423
+ * @param str произвольная строка
424
+ * @param colors массив CSS-цветов
425
+ * @returns один из цветов или null, если colors не передан
426
+ */
427
+ declare function getColorByString(str: string, colors?: string[]): string | null;
428
+
429
+ /**
430
+ * Хэлпер для создания строки URL адреса
431
+ * @example
432
+ * createPath('/library', { id: 1 }) // => /library?id=1
433
+ */
434
+ declare function createPath(u: string, query?: Record<string, string | number | boolean | null | undefined | Array<string | number | boolean | null | undefined>>): string;
435
+ /**
436
+ * Хэлпер для парсинга строки запроса (location.search)
437
+ * @example
438
+ * parseQueryString('?id=1') // => { id: '1' }
439
+ */
440
+ declare function parseQueryString(query: string): qs.ParsedQuery<string>;
441
+ /**
442
+ * Извлекает URL следующей страницы из HTTP заголовка Link
443
+ * @example
444
+ * getNextPageURLFromLinkHeader("<http://x/api?page=2>; rel='next'") // => 'http://x/api?page=2'
445
+ */
446
+ declare function getNextPageURLFromLinkHeader(link?: string): string;
447
+ /**
448
+ * Извлекает номер следующей страницы из HTTP заголовка Link
449
+ * @example
450
+ * getNextPageFromLinkHeader("<http://x/api?page=2>; rel='next'") // => 2
451
+ */
452
+ declare function getNextPageFromLinkHeader(link?: string): number | null;
453
+ /**
454
+ * Генерирует query-строку из объекта
455
+ */
456
+ declare function makeParamString(object?: Record<string, string | number | boolean | null | undefined>): string;
457
+
458
+ declare const mimeImages: () => string[];
459
+ declare const mimeFiles: () => string[];
460
+ declare const mimeAudio: () => string[];
461
+ declare const acceptFileTypes: () => string[];
462
+ declare const acceptAllTypes: () => string[];
463
+ declare const acceptImagesExtensions: () => string[];
464
+ declare const acceptFilesExtensions: () => string[];
465
+ declare const acceptAudioExtensions: () => string[];
466
+ declare const acceptAllExtensions: () => string[];
467
+
468
+ /**
469
+ * Оборачивает все имена полей query-строки в `wrapper[<field>]`, пропуская поля из `untouchables`.
470
+ *
471
+ * Пример:
472
+ * wrapFormFields('user', 'name=Alex&age=30', ['age'])
473
+ * -> 'user[name]=Alex&age=30'
474
+ */
475
+ declare function wrapFormFields(wrapper: string, formFieldsString: string, untouchables?: string[]): string;
476
+ /**
477
+ * Возвращает предикат, проверяющий, совпадает ли `id` объекта с `idToMatch`.
478
+ *
479
+ * Использование: arr.find(matchesId(id))
480
+ */
481
+ declare const matchesId: <T extends {
482
+ id: unknown;
483
+ }>(idToMatch: unknown) => (obj: T) => boolean;
484
+ /**
485
+ * Минимальная форма события для детекции клавиши Enter.
486
+ */
487
+ type KeyLikeEvent = {
488
+ which?: number;
489
+ keyCode?: number;
490
+ } | Pick<KeyboardEvent, 'which' | 'keyCode'>;
491
+ /**
492
+ * Определяет, была ли нажата клавиша Enter.
493
+ */
494
+ declare function detectEnterKey(e: KeyLikeEvent): boolean;
495
+ /**
496
+ * Собирает объект опции или возвращает `undefined`, если `value` — ложное значение.
497
+ * Примечание: сохраняет исходное поведение — `0`, пустая строка, false → `undefined`.
498
+ */
499
+ declare function makeOption<T>(value: T, label: string): {
500
+ value: T;
501
+ label: string;
502
+ } | undefined;
503
+ /**
504
+ * Создаёт загрузчик для асинхронных опций селекта.
505
+ *
506
+ * `func(args)` должен вернуть Promise с массивом опций или null/undefined.
507
+ * Если возвращается Promise, разрешённый `{ options }` объединяется с `extras`.
508
+ * Если возвращается null/undefined, используется `{ options: defaultOptions }` (плюс `extras`).
509
+ *
510
+ * `extras` сохраняет обратную совместимость со старым распространением (spread) значений по умолчанию.
511
+ */
512
+ declare function makeLoadOptionsFunc<O extends object, A = unknown>(func: (args: A) => Promise<O[]> | undefined | null, args: A, defaultOptions: O[], extras?: Record<string, unknown>): Promise<{
513
+ options: O[];
514
+ } & Record<string, unknown>>;
515
+
516
+ export { type AnyRecord, Collapse, type DangerousHTML, type FileLike, type HasGroupId, type MimeFiles, type PluralForms, type PluralizeType, type SelectOption, type SerializedField, type SourceOption, type StringMap, TYPES, acceptAllExtensions, acceptAllTypes, acceptAudioExtensions, acceptFileTypes, acceptFilesExtensions, acceptImagesExtensions, base64ToArrayBuffer, capitalize, colorLuminance, createPath, CURRENCY_DIRECTORY as currencyDirectory, debounce, detectEnterKey, detectIE, extractDigits, getColorByString, getCurrencySymbol, getFilesSize, getGradient, getMimeTypes, getNextPageFromLinkHeader, getNextPageURLFromLinkHeader, getRandomInt, indexByGroupId, indexById, isElementInViewport, makeLoadOptionsFunc, makeOption, makeParamString, makeShortNameFromFull, matchesId, merge, mergeByKey, mimeAudio, mimeFiles, mimeImages, outerHeight, parseQueryString, parseStringListToArray, pickBy, pluralize, pluralizeByType, qid, rawMarkup, removeElFromArr, scrollToElement, serializeArray, splitEvery, toCamelCase, toUnderscoredCase, transformOptionsForSelect, uniq, uuid, wrapFormFields };