prlg-ui 1.8.130 → 1.8.132

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 (71) hide show
  1. package/package.json +1 -1
  2. package/dist/FileIcon-BE4ItwkK.cjs +0 -1
  3. package/dist/FileIcon-maHE2Nhr.js +0 -101
  4. package/dist/Image-BHDBSn7B.cjs +0 -1
  5. package/dist/Image-CAGIshx9.js +0 -259
  6. package/dist/QuestionIcon-DptFSXX2.cjs +0 -1
  7. package/dist/QuestionIcon-tK1kUB_h.js +0 -340
  8. package/dist/SendIcon-CH6S0QWh.cjs +0 -1
  9. package/dist/SendIcon-Cqdt2QWN.js +0 -88
  10. package/dist/blocks/index.cjs.js +0 -1
  11. package/dist/blocks/index.es.js +0 -186
  12. package/dist/blocks.d.ts +0 -35
  13. package/dist/eventBus.util-K9Yq6hZm.cjs +0 -1
  14. package/dist/eventBus.util-msbJpg6N.js +0 -75
  15. package/dist/fonts/Roboto/Roboto-Black.woff +0 -0
  16. package/dist/fonts/Roboto/Roboto-Black.woff2 +0 -0
  17. package/dist/fonts/Roboto/Roboto-Bold.woff +0 -0
  18. package/dist/fonts/Roboto/Roboto-Bold.woff2 +0 -0
  19. package/dist/fonts/Roboto/Roboto-ExtraBold.woff +0 -0
  20. package/dist/fonts/Roboto/Roboto-ExtraBold.woff2 +0 -0
  21. package/dist/fonts/Roboto/Roboto-ExtraLight.woff +0 -0
  22. package/dist/fonts/Roboto/Roboto-ExtraLight.woff2 +0 -0
  23. package/dist/fonts/Roboto/Roboto-Light.woff +0 -0
  24. package/dist/fonts/Roboto/Roboto-Light.woff2 +0 -0
  25. package/dist/fonts/Roboto/Roboto-Medium.woff +0 -0
  26. package/dist/fonts/Roboto/Roboto-Medium.woff2 +0 -0
  27. package/dist/fonts/Roboto/Roboto-Regular.woff +0 -0
  28. package/dist/fonts/Roboto/Roboto-Regular.woff2 +0 -0
  29. package/dist/fonts/Roboto/Roboto-SemiBold.woff +0 -0
  30. package/dist/fonts/Roboto/Roboto-SemiBold.woff2 +0 -0
  31. package/dist/fonts/Roboto/Roboto-Thin.woff +0 -0
  32. package/dist/fonts/Roboto/Roboto-Thin.woff2 +0 -0
  33. package/dist/icons/index.cjs.js +0 -1
  34. package/dist/icons/index.es.js +0 -1487
  35. package/dist/icons.d.ts +0 -220
  36. package/dist/index.d.ts +0 -2096
  37. package/dist/parseFileSize.util-Bg1rLRLQ.cjs +0 -1
  38. package/dist/parseFileSize.util-CxVk4CvB.js +0 -785
  39. package/dist/prlg-ui.cjs.js +0 -1
  40. package/dist/prlg-ui.css +0 -1
  41. package/dist/prlg-ui.es.js +0 -6230
  42. package/dist/scss/animations.scss +0 -30
  43. package/dist/scss/colors.scss +0 -135
  44. package/dist/scss/fonts.scss +0 -3
  45. package/dist/scss/main.scss +0 -36
  46. package/dist/scss/mixins.scss +0 -177
  47. package/dist/scss/reset.scss +0 -51
  48. package/dist/scss/root-vars.scss +0 -12
  49. package/dist/types/index.cjs.js +0 -1
  50. package/dist/types/index.es.js +0 -1
  51. package/dist/types.d.ts +0 -14
  52. package/dist/uploadFile.util-DCFkx3w3.cjs +0 -1
  53. package/dist/uploadFile.util-DhavPrlY.js +0 -37
  54. package/dist/utils/date.util.ts +0 -30
  55. package/dist/utils/dayjs.util.ts +0 -32
  56. package/dist/utils/eventBus.util.ts +0 -43
  57. package/dist/utils/index.cjs.js +0 -1
  58. package/dist/utils/index.es.js +0 -1891
  59. package/dist/utils/index.ts +0 -3
  60. package/dist/utils/isClient.util.ts +0 -3
  61. package/dist/utils/mask.util.test.ts +0 -170
  62. package/dist/utils/mask.util.ts +0 -217
  63. package/dist/utils/onClickOutside.util.ts +0 -78
  64. package/dist/utils/parseDate.util.ts +0 -41
  65. package/dist/utils/parseFileSize.util.ts +0 -38
  66. package/dist/utils/price.util.ts +0 -28
  67. package/dist/utils/typeFile.util.ts +0 -32
  68. package/dist/utils/uploadFile.util.ts +0 -94
  69. package/dist/utils/useBodyScroll.util.ts +0 -41
  70. package/dist/utils.d.ts +0 -141
  71. package/dist/vite.svg +0 -1
@@ -1,3 +0,0 @@
1
- import Portal from "./Portal.vue";
2
-
3
- export { Portal };
@@ -1,3 +0,0 @@
1
- export default function isClient(): boolean {
2
- return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
3
- }
@@ -1,170 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest'
2
- import { Mask } from './mask.util'
3
-
4
- // Mock HTMLInputElement
5
- class MockHTMLInputElement {
6
- value: string = ''
7
-
8
- constructor() {}
9
- }
10
-
11
- describe('Mask', () => {
12
- let mask: Mask
13
- let mockInput: MockHTMLInputElement
14
-
15
- beforeEach(() => {
16
- mask = new Mask()
17
- mockInput = new MockHTMLInputElement()
18
- })
19
-
20
- const createEvent = (value: string): Event => {
21
- mockInput.value = value
22
- return { target: mockInput } as unknown as Event
23
- }
24
-
25
- describe('getDateMask', () => {
26
- it('должен ограничивать ввод только цифрами', () => {
27
- const event = createEvent('abc123def')
28
- mask.getDateMask(event)
29
- expect(mockInput.value).toBe('12.3')
30
- })
31
-
32
- it('должен применять маску dd.mm.yyyy по умолчанию', () => {
33
- const event = createEvent('12065678')
34
- mask.getDateMask(event)
35
- expect(mockInput.value).toBe('12.06.5678')
36
- })
37
-
38
- it('должен ограничивать длину ввода согласно формату', () => {
39
- const event = createEvent('120656789012345')
40
- mask.getDateMask(event)
41
- expect(mockInput.value).toBe('12.06.5678')
42
- })
43
-
44
- it('должен корректировать неправильный день больше 31', () => {
45
- const event = createEvent('3201')
46
- mask.getDateMask(event)
47
- expect(mockInput.value).toBe('31.01')
48
- })
49
-
50
- it('должен корректировать день 00 на 01', () => {
51
- const event = createEvent('0001')
52
- mask.getDateMask(event)
53
- expect(mockInput.value).toBe('01.01')
54
- })
55
-
56
- it('должен корректировать неправильный месяц больше 12', () => {
57
- const event = createEvent('0113')
58
- mask.getDateMask(event)
59
- expect(mockInput.value).toBe('01.12')
60
- })
61
-
62
- it('должен корректировать месяц 00 на 01', () => {
63
- const event = createEvent('0100')
64
- mask.getDateMask(event)
65
- expect(mockInput.value).toBe('01.01')
66
- })
67
-
68
- it('должен корректировать 31.06 на 30.06 (июнь имеет 30 дней)', () => {
69
- const event = createEvent('3106')
70
- mask.getDateMask(event)
71
- expect(mockInput.value).toBe('30.06')
72
- })
73
-
74
- it('должен корректировать 31.04 на 30.04 (апрель имеет 30 дней)', () => {
75
- const event = createEvent('3104')
76
- mask.getDateMask(event)
77
- expect(mockInput.value).toBe('30.04')
78
- })
79
-
80
- it('должен разрешать 31.01 (январь имеет 31 день)', () => {
81
- const event = createEvent('3101')
82
- mask.getDateMask(event)
83
- expect(mockInput.value).toBe('31.01')
84
- })
85
-
86
- it('должен разрешать 29.02 (максимум для февраля)', () => {
87
- const event = createEvent('2902')
88
- mask.getDateMask(event)
89
- expect(mockInput.value).toBe('29.02')
90
- })
91
-
92
- it('должен корректировать 30.02 на 29.02', () => {
93
- const event = createEvent('3002')
94
- mask.getDateMask(event)
95
- expect(mockInput.value).toBe('29.02')
96
- })
97
-
98
- it('должен не подставлять год если пользователь ввел только день и месяц', () => {
99
- const event = createEvent('1206')
100
- mask.getDateMask(event)
101
- expect(mockInput.value).toBe('12.06')
102
- expect(mockInput.value.length).toBe(5)
103
- })
104
-
105
- it('должен использовать автокоррекцию dayjs когда начинает вводить год', () => {
106
- const event = createEvent('31062025')
107
- mask.getDateMask(event)
108
- // dayjs скорректирует 31.06.2025 на 01.07.2025
109
- expect(mockInput.value).toBe('01.07.2025')
110
- })
111
-
112
- it('должен работать с частично введенным годом', () => {
113
- const event = createEvent('3106202')
114
- mask.getDateMask(event)
115
- // При частичном годе (7 символов, больше yearStart=6) используется dayjs
116
- // dayjs корректирует 31.06.2020 -> 01.07.2020, затем обрезается до 7 символов
117
- expect(mockInput.value).toBe('01.07.202')
118
- })
119
-
120
- it('должен принимать параметры minDate и maxDate без ошибок', () => {
121
- const event = createEvent('01012020')
122
- expect(() => {
123
- mask.getDateMask(event, 'dd.mm.yyyy', '01.01.2021')
124
- }).not.toThrow()
125
- })
126
-
127
- it('должен принимать параметры maxDate без ошибок', () => {
128
- const event = createEvent('01012025')
129
- expect(() => {
130
- mask.getDateMask(event, 'dd.mm.yyyy', undefined, '31.12.2024')
131
- }).not.toThrow()
132
- })
133
-
134
- it('должен не изменять дату если она в пределах minDate и maxDate', () => {
135
- const event = createEvent('15062023')
136
- mask.getDateMask(event, 'dd.mm.yyyy', '01.01.2023', '31.12.2023')
137
- expect(mockInput.value).toBe('15.06.2023')
138
- })
139
-
140
- it('должен работать с форматом mm.dd.yyyy', () => {
141
- const event = createEvent('12312023')
142
- mask.getDateMask(event, 'mm.dd.yyyy')
143
- expect(mockInput.value).toBe('12.31.2023')
144
- })
145
-
146
- it('должен корректировать неправильную дату в формате mm.dd.yyyy', () => {
147
- const event = createEvent('13312023')
148
- mask.getDateMask(event, 'mm.dd.yyyy')
149
- expect(mockInput.value).toBe('12.31.2023')
150
- })
151
-
152
- it('должен возвращать пустое значение если target не HTMLInputElement', () => {
153
- const event = { target: null } as unknown as Event
154
- mask.getDateMask(event)
155
- // Не должно выбросить ошибку
156
- })
157
-
158
- it('должен обрабатывать пустой ввод', () => {
159
- const event = createEvent('')
160
- mask.getDateMask(event)
161
- expect(mockInput.value).toBe('')
162
- })
163
-
164
- it('должен обрабатывать ввод одной цифры', () => {
165
- const event = createEvent('1')
166
- mask.getDateMask(event)
167
- expect(mockInput.value).toBe('1')
168
- })
169
- })
170
- })
@@ -1,217 +0,0 @@
1
- import { dayjs } from '../dayjs.util'
2
-
3
- export class Mask {
4
- public constructor() {
5
- }
6
-
7
- public getPhoneMask(_e: Event, _format: string = '(999) 999-99-99') {
8
-
9
- }
10
-
11
- public getDateMask(e: Event, format: string = 'dd.mm.yyyy', minDate?: string, maxDate?: string) {
12
- const input = e.target as HTMLInputElement
13
- if (!input) return
14
-
15
- let value = input.value.replace(/\D/g, '')
16
-
17
- const formatLength = format.replace(/\W/g, '').length
18
-
19
- if (value.length > formatLength) {
20
- value = value.slice(0, formatLength)
21
- }
22
-
23
- value = this.correctDateValues(value, format)
24
-
25
- let maskedValue = ''
26
- let valueIndex = 0
27
-
28
- for (let i = 0; i < format.length && valueIndex < value.length; i++) {
29
- const formatChar = format[i]
30
-
31
- if (formatChar === 'd' || formatChar === 'm' || formatChar === 'y') {
32
- maskedValue += value[valueIndex]
33
- valueIndex++
34
- } else {
35
- maskedValue += formatChar
36
- }
37
- }
38
-
39
- if (maskedValue.length >= format.length) {
40
- const parsedDate = this.parseDate(maskedValue, format)
41
- if (parsedDate && parsedDate.isValid()) {
42
- const correctedDate = this.applyDateLimits(maskedValue, format, minDate, maxDate)
43
- if (correctedDate) {
44
- maskedValue = correctedDate
45
- }
46
- }
47
- }
48
-
49
- input.value = maskedValue
50
- }
51
-
52
- private parseDate(value: string, format: string) {
53
- return dayjs(value, format.toLowerCase())
54
- }
55
-
56
- private correctDateValues(value: string, format: string): string {
57
- if (value.length < 2) return value
58
-
59
- const formatLower = format.toLowerCase()
60
- const dayIndex = formatLower.indexOf('dd')
61
- const monthIndex = formatLower.indexOf('mm')
62
-
63
- let correctedValue = value
64
-
65
- // Корректировка дня (01-31)
66
- if (dayIndex !== -1 && value.length >= 2) {
67
- const dayValue = parseInt(value.substring(0, 2))
68
- if (dayValue > 31) {
69
- correctedValue = '31' + value.substring(2)
70
- } else if (dayValue === 0) {
71
- correctedValue = '01' + value.substring(2)
72
- }
73
- }
74
-
75
- // Корректировка месяца (01-12)
76
- if (monthIndex !== -1 && correctedValue.length >= 4) {
77
- const monthStart = monthIndex === 0 ? 0 : 2
78
- const monthValue = parseInt(correctedValue.substring(monthStart, monthStart + 2))
79
- if (monthValue > 12) {
80
- correctedValue = correctedValue.substring(0, monthStart) + '12' + correctedValue.substring(monthStart + 2)
81
- } else if (monthValue === 0) {
82
- correctedValue = correctedValue.substring(0, monthStart) + '01' + correctedValue.substring(monthStart + 2)
83
- }
84
- }
85
-
86
- // Корректировка даты через dayjs (минимум 4 символа для дд.мм)
87
- if (correctedValue.length >= 4 && dayIndex !== -1 && monthIndex !== -1) {
88
- correctedValue = this.correctDateThroughDayjs(correctedValue, format)
89
- }
90
-
91
- return correctedValue
92
- }
93
-
94
- private correctDateThroughDayjs(value: string, format: string): string {
95
- const formatLower = format.toLowerCase()
96
- // const dayIndex = formatLower.indexOf('dd')
97
- // const monthIndex = formatLower.indexOf('mm')
98
- const yearIndex = formatLower.indexOf('yyyy')
99
-
100
- // const dayStart = dayIndex === 0 ? 0 : dayIndex === 3 ? 3 : 6
101
- // const monthStart = monthIndex === 0 ? 0 : monthIndex === 3 ? 3 : 6
102
- const yearStart = yearIndex === 0 ? 0 : yearIndex === 3 ? 3 : 6
103
-
104
- // Проверяем, есть ли минимум день и месяц (4 символа для dd.mm)
105
- if (value.length < 4) {
106
- return value
107
- }
108
-
109
- // Проверяем, начал ли пользователь вводить год
110
- const hasStartedYear = value.length > yearStart
111
- if (!hasStartedYear) {
112
- // Если год не начал вводить, только проверяем день/месяц без автокоррекции через dayjs
113
- return this.correctDayAndMonthOnly(value, format)
114
- }
115
-
116
- let maskedForParsing = ''
117
- let valueIndex = 0
118
-
119
- for (let i = 0; i < format.length && valueIndex < value.length; i++) {
120
- const formatChar = format[i]
121
-
122
- if (formatChar === 'd' || formatChar === 'm' || formatChar === 'y') {
123
- maskedForParsing += value[valueIndex] || '0'
124
- valueIndex++
125
- } else {
126
- maskedForParsing += formatChar
127
- }
128
- }
129
-
130
- // Если год не полный, дополняем текущим годом для валидации
131
- if (maskedForParsing.length < format.length) {
132
- const currentYear = new Date().getFullYear().toString()
133
- const missingLength = format.length - maskedForParsing.length
134
- maskedForParsing += currentYear.slice(-missingLength)
135
- }
136
-
137
- try {
138
- const parsedDate = dayjs(maskedForParsing, format.toUpperCase())
139
- if (parsedDate.isValid()) {
140
- const correctedDateString = parsedDate.format(format.toUpperCase())
141
- const correctedDigits = correctedDateString.replace(/\D/g, '')
142
- // Возвращаем только то количество цифр, которое пользователь ввел
143
- return correctedDigits.substring(0, value.length)
144
- }
145
- } catch (e) {
146
- // Если парсинг не удался, возвращаем исходное значение
147
- }
148
-
149
- return value
150
- }
151
-
152
- private correctDayAndMonthOnly(value: string, format: string): string {
153
- const formatLower = format.toLowerCase()
154
- const dayIndex = formatLower.indexOf('dd')
155
- const monthIndex = formatLower.indexOf('mm')
156
-
157
- const dayStart = dayIndex === 0 ? 0 : dayIndex === 3 ? 3 : 6
158
- const monthStart = monthIndex === 0 ? 0 : monthIndex === 3 ? 3 : 6
159
-
160
- // Минимум нужно 4 символа для dd.mm
161
- if (value.length < 4) return value
162
-
163
- const day = parseInt(value.substring(dayStart, dayStart + 2))
164
- const month = parseInt(value.substring(monthStart, monthStart + 2))
165
-
166
- if (!day || !month) return value
167
-
168
- // Определяем количество дней в месяце
169
- const daysInMonth = this.getDaysInMonth(month)
170
-
171
- if (day > daysInMonth) {
172
- const correctedDay = daysInMonth.toString().padStart(2, '0')
173
- return value.substring(0, dayStart) + correctedDay + value.substring(dayStart + 2)
174
- }
175
-
176
- return value
177
- }
178
-
179
- private getDaysInMonth(month: number): number {
180
- const daysInMonths = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
181
- if (month < 1 || month > 12) return 31
182
- return daysInMonths[month - 1]
183
- }
184
-
185
- private applyDateLimits(dateString: string, format: string, minDate?: string, maxDate?: string): string | null {
186
- if (!minDate && !maxDate) {
187
- return null
188
- }
189
-
190
- const parsedDate = this.parseDate(dateString, format)
191
-
192
- if (!parsedDate || !parsedDate.isValid()) {
193
- return null
194
- }
195
-
196
- let correctedDate = parsedDate
197
- let hasChanges = false
198
-
199
- if (minDate) {
200
- const minDateObj = dayjs(minDate)
201
- if (correctedDate.isBefore(minDateObj)) {
202
- correctedDate = minDateObj
203
- hasChanges = true
204
- }
205
- }
206
-
207
- if (maxDate) {
208
- const maxDateObj = dayjs(maxDate)
209
- if (correctedDate.isAfter(maxDateObj)) {
210
- correctedDate = maxDateObj
211
- hasChanges = true
212
- }
213
- }
214
-
215
- return hasChanges ? correctedDate.format(format.toUpperCase()) : null
216
- }
217
- }
@@ -1,78 +0,0 @@
1
- import type { ComponentPublicInstance, MaybeRef, MaybeRefOrGetter } from 'vue';
2
- import { unref, toValue } from 'vue';
3
-
4
- export type VueInstance = ComponentPublicInstance;
5
- export type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null;
6
- export type MaybeElementRef<T extends MaybeElement = MaybeElement> = MaybeRef<T>;
7
- export type MaybeElementTarget = MaybeElementRef<MaybeElement> | string;
8
-
9
- export interface OnClickOutsideOptions {
10
- ignore?: MaybeRefOrGetter<(MaybeElementRef<MaybeElement> | string)[]>;
11
- }
12
-
13
- const activeListeners = new WeakMap<HTMLElement, () => void>();
14
-
15
- function unrefElement(elRef: MaybeElementRef<MaybeElement>): HTMLElement | null {
16
- const plain = unref(elRef);
17
- return (plain as VueInstance)?.$el ?? (plain as HTMLElement | null);
18
- }
19
-
20
- function resolveTarget(target: MaybeElementTarget): HTMLElement | null {
21
- if (typeof target === 'string') {
22
- return document.querySelector(target) as HTMLElement | null;
23
- }
24
- return unrefElement(target);
25
- }
26
-
27
- export function onClickOutside(
28
- target: MaybeElementTarget,
29
- handler: (event: MouseEvent | TouchEvent) => void,
30
- options: OnClickOutsideOptions = {}
31
- ): () => void {
32
- const targetElement = resolveTarget(target);
33
- if (!targetElement) return () => {};
34
-
35
- // Remove existing listener if present
36
- const existingCleanup = activeListeners.get(targetElement);
37
- if (existingCleanup) {
38
- existingCleanup();
39
- activeListeners.delete(targetElement);
40
- }
41
-
42
- const listener = (event: MouseEvent | TouchEvent) => {
43
- const targetNode = event.target instanceof Node ? event.target : null;
44
- if (!targetNode) return;
45
-
46
- const rawIgnores = toValue(options.ignore) ?? [];
47
- const ignoreElements = rawIgnores
48
- .map(el => {
49
- if (typeof el === 'string') {
50
- return document.querySelector(el) as HTMLElement | null;
51
- }
52
- return unrefElement(el);
53
- })
54
- .filter((el): el is HTMLElement => el !== null && el !== undefined);
55
-
56
- if (
57
- targetElement.contains(targetNode) ||
58
- ignoreElements.some(ignoreEl => ignoreEl.contains(targetNode))
59
- ) {
60
- return;
61
- }
62
-
63
- handler(event);
64
- };
65
-
66
- document.addEventListener('mousedown', listener, { capture: true });
67
- document.addEventListener('touchstart', listener, { capture: true });
68
-
69
- // Store cleanup function and return it
70
- const cleanup = () => {
71
- document.removeEventListener('mousedown', listener, { capture: true });
72
- document.removeEventListener('touchstart', listener, { capture: true });
73
- activeListeners.delete(targetElement);
74
- };
75
- activeListeners.set(targetElement, cleanup);
76
-
77
- return cleanup;
78
- }
@@ -1,41 +0,0 @@
1
- function parseDurationToSeconds(duration: string): number {
2
- const regex = /^(\d+)(s|m|h|d|day|month|year)$/;
3
- const match = duration.match(regex);
4
-
5
- if (!match) {
6
- throw new Error('Invalid duration format. Use formats like 30d, 1m, 1h, 1day, 1month, 1year');
7
- }
8
-
9
- const value = parseInt(match[1], 10);
10
- const unit = match[2];
11
-
12
- switch (unit) {
13
- case 's':
14
- return value; // seconds
15
- case 'm':
16
- return value * 60; // minutes
17
- case 'h':
18
- return value * 3600; // hours
19
- case 'd':
20
- case 'day':
21
- return value * 86400; // days
22
- case 'month':
23
- return value * 2592000; // months (30 days)
24
- case 'year':
25
- return value * 31536000; // years (365 days)
26
- default:
27
- throw new Error('Unsupported time unit');
28
- }
29
- }
30
-
31
- export default parseDurationToSeconds;
32
-
33
- /** Примеры использования */
34
- /** example
35
- console.log(parseDurationToSeconds('30d')); // 2592000
36
- console.log(parseDurationToSeconds('1m')); // 60
37
- console.log(parseDurationToSeconds('1h')); // 3600
38
- console.log(parseDurationToSeconds('1day')); // 86400
39
- console.log(parseDurationToSeconds('1month')); // 2592000
40
- console.log(parseDurationToSeconds('1year')); // 31536000
41
- */
@@ -1,38 +0,0 @@
1
- /**
2
- * Преобразует строку с размером файла (например, "5mb", "10kb", "1.5gb") в число байт.
3
- *
4
- * @param {string} size - Строка, содержащая числовое значение и единицу измерения (b, kb, mb, gb, tb).
5
- * Пример: "5mb", "10kb", "1.5gb".
6
- * @returns {number} - Размер в байтах.
7
- *
8
- * Поддерживаемые единицы: b, kb, mb, gb, tb (регистр не имеет значения).
9
- * Если единица не указана, по умолчанию считается "b" (байты).
10
- */
11
-
12
- export const parseFileSize = (size: string): number => {
13
- const units = ['b', 'kb', 'mb', 'gb', 'tb'];
14
- const unit = size.match(/[a-zA-Z]+/)?.[0] || 'b';
15
- const value = parseFloat(size.replace(unit, ''));
16
- const index = units.indexOf(unit.toLowerCase());
17
- return value * Math.pow(1024, index);
18
- }
19
-
20
- /**
21
- * Преобразует размер файла в байтах в человекочитаемый текст (например, "1.5 МБ").
22
- *
23
- * @param {number} bytes - Размер файла в байтах.
24
- * @returns {string} - Размер файла в виде строки с подходящей единицей (Б, КБ, МБ, ГБ, ТБ).
25
- */
26
- export function formatFileSize(bytes: number): string {
27
- if (isNaN(bytes) || bytes < 0) return '0 Б';
28
- const units = ['Б', 'КБ', 'МБ', 'ГБ', 'ТБ'];
29
- let index = 0;
30
- let value = bytes;
31
- while (value >= 1024 && index < units.length - 1) {
32
- value = value / 1024;
33
- index++;
34
- }
35
- // Округляем до одного знака после запятой, если нужно
36
- const rounded = value % 1 === 0 ? value : value.toFixed(0);
37
- return `${rounded} ${units[index]}`;
38
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * Преобразует число в форматированную строку с валютой (по умолчанию: ₽)
3
- */
4
- export function formatPrice(value: number, currency = "₽"): string {
5
- // Используем en-US локаль для точки как разделителя дробной части
6
- // и заставляем всегда показывать ровно 2 знака после точки
7
- const formatted = value.toLocaleString("en-US", {
8
- minimumFractionDigits: 2,
9
- maximumFractionDigits: 2
10
- }).replace(/,/g, " ");
11
-
12
- return `${formatted} ${currency}`;
13
- }
14
-
15
- /**
16
- * Возвращает сумму всех значений (например, для корзины)
17
- */
18
- export function sumPrices(items: number[]): number {
19
- return items.reduce((total, price) => total + price, 0);
20
- }
21
-
22
- /**
23
- * Делает безопасное преобразование строки в число (цены из инпута)
24
- */
25
- export function parsePrice(input: string): number {
26
- const normalized = input.replace(/[^\d.,]/g, "").replace(",", ".");
27
- return parseFloat(normalized) || 0;
28
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Определяет тип файла по его MIME-типу.
3
- * Возвращает 'image' для изображений, 'pdf' для PDF-файлов,
4
- * 'word' для документов Word, 'excel' для файлов Excel,
5
- * иначе 'other'.
6
- *
7
- * @param {string} mimeType - MIME-тип файла
8
- * @returns {'image' | 'pdf' | 'word' | 'excel' | 'other'}
9
- */
10
- export function getFileTypeByMime(
11
- mimeType: string
12
- ): 'image' | 'pdf' | 'word' | 'excel' | 'other' {
13
- if (mimeType.startsWith('image/')) {
14
- return 'image';
15
- }
16
- if (mimeType === 'application/pdf') {
17
- return 'pdf';
18
- }
19
- if (
20
- mimeType === 'application/msword' ||
21
- mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
22
- ) {
23
- return 'word';
24
- }
25
- if (
26
- mimeType === 'application/vnd.ms-excel' ||
27
- mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
28
- ) {
29
- return 'excel';
30
- }
31
- return 'other';
32
- }