prlg-ui 1.8.132 → 1.8.133

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/dist/FileIcon-BE4ItwkK.cjs +1 -0
  2. package/dist/FileIcon-maHE2Nhr.js +101 -0
  3. package/dist/Image-BHDBSn7B.cjs +1 -0
  4. package/dist/Image-CAGIshx9.js +259 -0
  5. package/dist/QuestionIcon-DptFSXX2.cjs +1 -0
  6. package/dist/QuestionIcon-tK1kUB_h.js +340 -0
  7. package/dist/SendIcon-CH6S0QWh.cjs +1 -0
  8. package/dist/SendIcon-Cqdt2QWN.js +88 -0
  9. package/dist/blocks/index.cjs.js +1 -0
  10. package/dist/blocks/index.es.js +186 -0
  11. package/dist/blocks.d.ts +35 -0
  12. package/dist/eventBus.util-K9Yq6hZm.cjs +1 -0
  13. package/dist/eventBus.util-msbJpg6N.js +75 -0
  14. package/dist/fonts/Roboto/Roboto-Black.woff +0 -0
  15. package/dist/fonts/Roboto/Roboto-Black.woff2 +0 -0
  16. package/dist/fonts/Roboto/Roboto-Bold.woff +0 -0
  17. package/dist/fonts/Roboto/Roboto-Bold.woff2 +0 -0
  18. package/dist/fonts/Roboto/Roboto-ExtraBold.woff +0 -0
  19. package/dist/fonts/Roboto/Roboto-ExtraBold.woff2 +0 -0
  20. package/dist/fonts/Roboto/Roboto-ExtraLight.woff +0 -0
  21. package/dist/fonts/Roboto/Roboto-ExtraLight.woff2 +0 -0
  22. package/dist/fonts/Roboto/Roboto-Light.woff +0 -0
  23. package/dist/fonts/Roboto/Roboto-Light.woff2 +0 -0
  24. package/dist/fonts/Roboto/Roboto-Medium.woff +0 -0
  25. package/dist/fonts/Roboto/Roboto-Medium.woff2 +0 -0
  26. package/dist/fonts/Roboto/Roboto-Regular.woff +0 -0
  27. package/dist/fonts/Roboto/Roboto-Regular.woff2 +0 -0
  28. package/dist/fonts/Roboto/Roboto-SemiBold.woff +0 -0
  29. package/dist/fonts/Roboto/Roboto-SemiBold.woff2 +0 -0
  30. package/dist/fonts/Roboto/Roboto-Thin.woff +0 -0
  31. package/dist/fonts/Roboto/Roboto-Thin.woff2 +0 -0
  32. package/dist/icons/index.cjs.js +1 -0
  33. package/dist/icons/index.es.js +1487 -0
  34. package/dist/icons.d.ts +220 -0
  35. package/dist/index.d.ts +2096 -0
  36. package/dist/parseFileSize.util-Bg1rLRLQ.cjs +1 -0
  37. package/dist/parseFileSize.util-CxVk4CvB.js +785 -0
  38. package/dist/prlg-ui.cjs.js +1 -0
  39. package/dist/prlg-ui.css +1 -0
  40. package/dist/prlg-ui.es.js +6227 -0
  41. package/dist/scss/animations.scss +30 -0
  42. package/dist/scss/colors.scss +135 -0
  43. package/dist/scss/fonts.scss +3 -0
  44. package/dist/scss/main.scss +36 -0
  45. package/dist/scss/mixins.scss +177 -0
  46. package/dist/scss/reset.scss +51 -0
  47. package/dist/scss/root-vars.scss +12 -0
  48. package/dist/types/index.cjs.js +1 -0
  49. package/dist/types/index.es.js +1 -0
  50. package/dist/types.d.ts +14 -0
  51. package/dist/uploadFile.util-DCFkx3w3.cjs +1 -0
  52. package/dist/uploadFile.util-DhavPrlY.js +37 -0
  53. package/dist/utils/date.util.ts +30 -0
  54. package/dist/utils/dayjs.util.ts +32 -0
  55. package/dist/utils/eventBus.util.ts +43 -0
  56. package/dist/utils/index.cjs.js +1 -0
  57. package/dist/utils/index.es.js +1891 -0
  58. package/dist/utils/index.ts +3 -0
  59. package/dist/utils/isClient.util.ts +3 -0
  60. package/dist/utils/mask.util.test.ts +170 -0
  61. package/dist/utils/mask.util.ts +217 -0
  62. package/dist/utils/onClickOutside.util.ts +78 -0
  63. package/dist/utils/parseDate.util.ts +41 -0
  64. package/dist/utils/parseFileSize.util.ts +38 -0
  65. package/dist/utils/price.util.ts +28 -0
  66. package/dist/utils/typeFile.util.ts +32 -0
  67. package/dist/utils/uploadFile.util.ts +94 -0
  68. package/dist/utils/useBodyScroll.util.ts +41 -0
  69. package/dist/utils.d.ts +141 -0
  70. package/dist/vite.svg +1 -0
  71. package/package.json +1 -1
@@ -0,0 +1,30 @@
1
+ .slide-fade-smooth-enter-active,
2
+ .slide-fade-smooth-leave-active {
3
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
4
+ }
5
+
6
+ .slide-fade-smooth-enter-from {
7
+ transform: translateX(-30px);
8
+ opacity: 0;
9
+ }
10
+
11
+ .slide-fade-smooth-leave-to {
12
+ transform: translateX(30px);
13
+ opacity: 0;
14
+ }
15
+
16
+ // VERTICAL SLIDE FADE
17
+ .slide-fade-vertical-enter-active,
18
+ .slide-fade-vertical-leave-active {
19
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
20
+ }
21
+
22
+ .slide-fade-vertical-enter-from {
23
+ transform: translateY(-20px);
24
+ opacity: 0;
25
+ }
26
+
27
+ .slide-fade-vertical-leave-to {
28
+ transform: translateY(20px);
29
+ opacity: 0;
30
+ }
@@ -0,0 +1,135 @@
1
+ //GLOBAL
2
+ :root {
3
+ --theme-color-m: #E3E9ED;
4
+ --animate-duration: 0.3s;
5
+ }
6
+
7
+ //NEUTRAL
8
+ :root {
9
+ --theme-neutral-0: #ffffff;
10
+ --theme-neutral-100: #FDFDFD; //use bg main fill
11
+ --theme-neutral-200: #FAFAFA;
12
+ --theme-neutral-250: #EBEBEB;
13
+ --theme-neutral-250_40: #EBEBEB66; //use dissabled fill
14
+ --theme-neutral-300: #CECECE; //use border icon,text
15
+ --theme-neutral-300_40: #CECECE66; //use hover table fill
16
+ --theme-neutral-400: #BFBFBF;
17
+ --theme-neutral-400_40: #BFBFBF66;
18
+ --theme-neutral-500: #A1A1A1; //use btn icon
19
+ --theme-neutral-600: #525252;
20
+ --theme-neutral-700: #3D3D3D;
21
+ --theme-neutral-800: #292929;
22
+ --theme-neutral-850: #1F1F1F;
23
+ --theme-neutral-950: #0A0A0A;
24
+
25
+ --theme-neutral-surface-bg: var(--theme-neutral-100);
26
+ --theme-neutral-surface-default: var(--theme-neutral-0);
27
+ --theme-neutral-surface-subtitle: var(--theme-neutral-200);
28
+ --theme-neutral-surface-icon: #F1F4F5;
29
+ --theme-neutral-surface-disabled: var(--theme-neutral-250_40);
30
+
31
+ --theme-text-icon-body: #3B3B3B;
32
+ --theme-neutral-text-title: var(--theme-neutral-950);
33
+ --theme-neutral-text-subtitle: var(--theme-neutral-800);
34
+ --theme-neutral-text-body: var(--theme-neutral-700);
35
+ --theme-neutral-text-caption: var(--theme-neutral-500);
36
+ --theme-neutral-text-disabled: var(--theme-neutral-400_40);
37
+ --theme-neutral-text-negative: var(--theme-neutral-0);
38
+
39
+ --theme-neutral-icon-primary: #90A4AE;
40
+ --theme-neutral-icon-secondary: var(--theme-neutral-400);
41
+ --theme-neutral-icon-caption: var(--theme-neutral-500);
42
+ --theme-neutral-icon-disabled: #B5B5B5;
43
+ --theme-neutral-icon-negative: var(--theme-neutral-0);
44
+
45
+ --theme-neutral-border-default: var(--theme-neutral-300);
46
+ --theme-neutral-border-darker: var(--theme-neutral-400);
47
+ --theme-neutral-border-divider: #E3E9ED;
48
+ --theme-neutral-border-disabled: var(--theme-neutral-400_40);
49
+
50
+ //BOX-SHADOW
51
+ --theme-main-interface-shadow: 0 2px 8.8px 2px #0000000D, 0 0 13.4px 0 #0000000A;
52
+ --theme-hover-interface-shadow: 0 2px 8.8px 2px #0000000D, 0 1px 1px 0 #0000000A;
53
+
54
+ }
55
+
56
+ //PRIMARY
57
+ :root {
58
+ --theme-primary-50: #EAFEF0;
59
+ --theme-primary-50_40: #EAFEF066;
60
+ --theme-primary-75: #CAF3D5; //use hover fill
61
+ --theme-primary-100: #BFF7CD;
62
+ --theme-primary-200: #AAEEBC;
63
+ --theme-primary-200_15: #94E6AA; //use focussed stroke
64
+ --theme-primary-200_25: #94E6AA40; //use focussed stroke
65
+ --theme-primary-200_50: #94E6AA80; //use focussed stroke
66
+ --theme-primary-250: #CAF3D5; //use hover fill
67
+ --theme-primary-300: #7FDD98; //use hover fill
68
+ --theme-primary-400: #2ABC51; //use focussed fill
69
+ --theme-primary-500_5: #00AB2E0D; //use default fill
70
+ --theme-primary-500: #00AB2E; //use default fill
71
+ --theme-primary-600: #008925; //use pressed fill
72
+ --theme-primary-700: #00671C;
73
+ --theme-primary-800: #004412;
74
+ --theme-primary-900: #002209;
75
+
76
+ --theme-primary-surface-default: var(--theme-primary-500);
77
+ --theme-primary-surface-subtitle: var(--theme-primary-50);
78
+ --theme-primary-surface-darker: var(--theme-primary-600);
79
+ --theme-primary-surface-lighter: var(--theme-primary-200_25);
80
+ --theme-primary-surface-hover: var(--theme-primary-50_40);
81
+
82
+ --theme-primary-border-default: var(--theme-primary-700);
83
+ --theme-primary-border-subtitle: var(--theme-primary-600);
84
+ --theme-primary-border-darker: var(--theme-primary-800);
85
+ --theme-primary-border-lighter: var(--theme-primary-200);
86
+
87
+ --theme-primary-icon-default: var(--theme-primary-500);
88
+ }
89
+
90
+ //INFO
91
+ :root {
92
+ --theme-info-100: #E3EEFA;
93
+ --theme-info-100_50: #E3EEFA80; //use fill
94
+ --theme-info-200: #C2D9F5; //use stroke
95
+ --theme-info-300: #6EA6E7; //hover
96
+ --theme-info-400: #2674CE; //use link (подчеркивание при наведении)
97
+ --theme-info-500: #235FA4; //use icon
98
+ --theme-info-600: #02538F;
99
+ --theme-info-700: #134A73;
100
+ --theme-info-800: #152D4F;
101
+ --theme-info-900: #161E33;
102
+ }
103
+
104
+ //WARN
105
+ :root {
106
+ --theme-warn-100: #FDF4EA; //use fill
107
+ --theme-warn-200: #FADFC1; //use stroke
108
+ --theme-warn-300: #F4C083; //hover
109
+ --theme-warn-400: #F1AB5A;
110
+ --theme-warn-500: #ED9631; //use icon
111
+ --theme-warn-600: #D47D16;
112
+ --theme-warn-700: #AC6410;
113
+ --theme-warn-800: #814A09;
114
+ --theme-warn-900: #492C0A;
115
+ }
116
+
117
+ //ERROR
118
+ :root {
119
+ --theme-error-100: #FCEAEA;
120
+ --theme-error-100_50: #FCEAEA80; //use fill
121
+ --theme-error-200_50: #FCEAEA; //use stroke
122
+ --theme-error-200: #FFD4D4; //use stroke
123
+ --theme-error-300: #F4A6A6; //hover
124
+ --theme-error-400: #DF575C;
125
+ --theme-error-500: #DE292F; //use icon
126
+ --theme-error-600: #BD2429;
127
+ --theme-error-700: #921D21;
128
+ --theme-error-800: #6E1820;
129
+ --theme-error-900: #4E1012;
130
+ }
131
+
132
+ //SHADOW
133
+ :root {
134
+ --theme-shadow-button: 0px 2px 8.8px 2px #0000000D, 0px 1px 1px 0px #0000000A;
135
+ }
@@ -0,0 +1,3 @@
1
+ @use "./mixins.scss" as mixins;
2
+
3
+ @include mixins.font-face("Roboto", (100, 200, 300, 400, 500, 600, 700, 800, 900));
@@ -0,0 +1,36 @@
1
+ @use './reset.scss';
2
+ @use './colors.scss';
3
+ @use './root-vars.scss';
4
+ @use './mixins.scss' as *;
5
+ @use './fonts.scss';
6
+
7
+ .container {
8
+ width: 100%;
9
+ margin: 0 auto;
10
+ padding: 0 10px;
11
+ max-width: 768px; // Базовая ширина для мобильных
12
+
13
+ @include respond(lg) {
14
+ max-width: 991px;
15
+ }
16
+
17
+ @include respond(xl) {
18
+ max-width: 1200px;
19
+ }
20
+
21
+ @include respond(xxl) {
22
+ max-width: 1400px;
23
+ }
24
+
25
+ @include respond(xxxl) {
26
+ max-width: 1600px;
27
+ }
28
+ }
29
+
30
+ .page-title {
31
+ font-weight: 600;
32
+ font-size: 24px;
33
+ line-height: 120%;
34
+ color: var(--theme-neutral-text-title);
35
+ text-transform: uppercase;
36
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Миксин для подключения шрифтов
3
+ * @param {string} $font-family - Название семейства шрифтов
4
+ * @param {list} $weights - Список весов шрифта (100-900)
5
+ *
6
+ * Пример использования:
7
+ * $weights: (100, 200, 300, 400, 500, 600, 700, 800, 900);
8
+ * $styles: (normal, italic);
9
+ * @include font-face('Roboto', $weights);
10
+ *
11
+ * Структура файлов шрифтов должна быть следующей:
12
+ * fonts/
13
+ * Roboto/
14
+ * Roboto-Thin.woff2
15
+ * Roboto-Thin.woff
16
+ * ...
17
+ */
18
+
19
+ @mixin font-face($font-family, $weights) {
20
+ @each $weight in $weights {
21
+ $weight-name: if(
22
+ $weight == 100,
23
+ "Thin",
24
+ if(
25
+ $weight == 200,
26
+ "ExtraLight",
27
+ if(
28
+ $weight == 300,
29
+ "Light",
30
+ if(
31
+ $weight == 400,
32
+ "Regular",
33
+ if(
34
+ $weight == 500,
35
+ "Medium",
36
+ if(
37
+ $weight == 600,
38
+ "SemiBold",
39
+ if(
40
+ $weight == 700,
41
+ "Bold",
42
+ if(
43
+ $weight == 800,
44
+ "ExtraBold",
45
+ if($weight == 900, "Black", $weight)
46
+ )
47
+ )
48
+ )
49
+ )
50
+ )
51
+ )
52
+ )
53
+ );
54
+ @font-face {
55
+ font-family: "#{$font-family}";
56
+ font-weight: #{$weight};
57
+ src: url("/fonts/#{$font-family}/#{$font-family}-#{$weight-name}.woff2") format("woff2"),
58
+ url("/fonts/#{$font-family}/#{$font-family}-#{$weight-name}.woff") format("woff");
59
+ }
60
+ }
61
+ }
62
+
63
+
64
+ /**
65
+ * Миксин для создания медиа-запросов с минимальной шириной
66
+ *
67
+ * @param {number} $width - Минимальная ширина в пикселях
68
+ *
69
+ * Пример использования:
70
+ * @include media-min-width(768px) {
71
+ * .container {
72
+ * padding: 20px;
73
+ * }
74
+ * }
75
+ *
76
+ * Применит стили для экранов шириной от 768px и больше
77
+ */
78
+
79
+
80
+ @mixin media-min-width($width) {
81
+ @media screen and (min-width: $width) {
82
+ @content;
83
+ }
84
+ }
85
+
86
+ /// Миксин для обрезки многострочного текста с троеточием
87
+ ///
88
+ /// @param {Number} $lines - Количество отображаемых строк (по умолчанию: 2)
89
+ ///
90
+ /// Используется для ограничения текста по количеству строк с добавлением "..."
91
+ /// Работает на основе -webkit-line-clamp и поддерживается в современных браузерах.
92
+ ///
93
+ /// 🔁 Пример использования:
94
+ /// .text {
95
+ /// @include ellipsis-multiline(3);
96
+ /// }
97
+ @mixin ellipsis-multiline($lines: 2) {
98
+ display: -webkit-box;
99
+ -webkit-line-clamp: $lines;
100
+ -webkit-box-orient: vertical;
101
+ overflow: hidden;
102
+ text-overflow: ellipsis;
103
+ }
104
+
105
+ // 📱 Адаптив
106
+ @mixin respond($breakpoint) {
107
+ @if $breakpoint == sm {
108
+ @media (min-width: 640px) {
109
+ @content;
110
+ }
111
+ } @else if $breakpoint == md {
112
+ @media (min-width: 768px) {
113
+ @content;
114
+ }
115
+ } @else if $breakpoint == lg {
116
+ @media (min-width: 1010px) {
117
+ @content;
118
+ }
119
+ } @else if $breakpoint == xl {
120
+ @media (min-width: 1220px) {
121
+ @content;
122
+ }
123
+ } @else if $breakpoint == xxl {
124
+ @media (min-width: 1420px) {
125
+ @content;
126
+ }
127
+ } @else if $breakpoint == xxxl {
128
+ @media (min-width: 1620px) {
129
+ @content;
130
+ }
131
+ }
132
+ }
133
+
134
+ // ✨ Кастомный скроллбар
135
+ @mixin custom-scrollbar($direction) {
136
+ box-sizing: content-box;
137
+
138
+ scrollbar-width: thin;
139
+ scrollbar-color: var(--theme-neutral-border-default) transparent;
140
+
141
+ // WebKit scrollbar
142
+ &::-webkit-scrollbar {
143
+ @if $direction == "right" {
144
+ width: 8px;
145
+ height: 0;
146
+ } @else if $direction == "bottom" {
147
+ width: 0;
148
+ height: 8px;
149
+ } @else if $direction == "both" {
150
+ width: 8px;
151
+ height: 8px;
152
+ }
153
+ }
154
+
155
+ &::-webkit-scrollbar-thumb {
156
+ background-color: var(--theme-neutral-border-default);
157
+ border-radius: 4px;
158
+ }
159
+
160
+ &::-webkit-scrollbar-track {
161
+ background: transparent;
162
+ }
163
+
164
+ &::-webkit-scrollbar-corner {
165
+ background: transparent;
166
+ }
167
+
168
+ // Add paddings depending on direction
169
+ // @if $direction == "right" {
170
+ // padding-right: 10px;
171
+ // } @else if $direction == "bottom" {
172
+ // padding-bottom: 10px;
173
+ // } @else if $direction == "both" {
174
+ // padding-right: 10px;
175
+ // padding-bottom: 10px;
176
+ // }
177
+ }
@@ -0,0 +1,51 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ html, body {
8
+ height: 100%;
9
+ width: 100%;
10
+ }
11
+
12
+ body {
13
+ font-family: "Roboto", sans-serif;
14
+ -webkit-font-smoothing: antialiased;
15
+ -moz-osx-font-smoothing: grayscale;
16
+ font-size: 16px;
17
+ line-height: 1.5;
18
+ color: #333;
19
+ }
20
+
21
+ a {
22
+ text-decoration: none;
23
+ color: inherit;
24
+ }
25
+
26
+ button {
27
+ border: none;
28
+ background: none;
29
+ cursor: pointer;
30
+ font: inherit;
31
+ }
32
+
33
+ ul, ol {
34
+ list-style: none;
35
+ }
36
+
37
+ img {
38
+ max-width: 100%;
39
+ height: auto;
40
+ display: block;
41
+ }
42
+
43
+ input, textarea, select {
44
+ font: inherit;
45
+ border: none;
46
+ outline: none;
47
+ }
48
+
49
+ h1, h2, h3, h4, h5, h6 {
50
+ font-weight: normal;
51
+ }
@@ -0,0 +1,12 @@
1
+ //MODAL
2
+ :root {
3
+ --modal-z-index: 1000;
4
+ --drawer-z-index: 1000;
5
+ --confirm-z-index: 1008;
6
+ --toast-z-index: 1009;
7
+
8
+ //BOX-SHADOW
9
+ --dropdown-shadow: -1px 1px 10px 0 #8D8F9340;
10
+ --popover-shadow: 0 12px 25px 0 #0000001A, 0 0 8px 0 #0000001A;
11
+
12
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,14 @@
1
+ import { Component } from 'vue';
2
+ import { RouteLocationRaw } from 'vue-router';
3
+
4
+ export declare type MenuItem = {
5
+ icon?: Component;
6
+ label: string;
7
+ url?: string | RouteLocationRaw;
8
+ command?: () => void;
9
+ description?: string;
10
+ badge?: boolean;
11
+ disabled?: boolean;
12
+ };
13
+
14
+ export { }
@@ -0,0 +1 @@
1
+ "use strict";const s=require("./parseFileSize.util-Bg1rLRLQ.cjs");function o(e){if(!e)return;const a=Array.isArray(e)?e:[e],i={image:["image/*"],pdf:["application/pdf"],excel:["application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],word:["application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"],all:["*/*"]};return a.flatMap(t=>i[t]||[]).join(",")}function d(e={}){return new Promise(a=>{const i=document.createElement("input");i.type="file",i.style.display="none",e.multiple&&e.maxFiles&&e.maxFiles>1&&(i.multiple=!0);const t=o(e.accept);t&&(i.accept=t),i.addEventListener("change",r=>{const n=r.target;let l=[];if(n.files&&n.files.length>0&&(l=Array.from(n.files),e.maxFiles&&l.length>e.maxFiles&&(l=l.slice(0,e.maxFiles)),e.maxFileSize)){const c=s.parseFileSize(e.maxFileSize);l=l.filter(m=>m.size<=c)}a(l),document.body.removeChild(i)}),document.body.appendChild(i),i.click()})}exports.openFileDialog=d;
@@ -0,0 +1,37 @@
1
+ import { p as o } from "./parseFileSize.util-CxVk4CvB.js";
2
+ function s(e) {
3
+ if (!e) return;
4
+ const a = Array.isArray(e) ? e : [e], i = {
5
+ image: ["image/*"],
6
+ pdf: ["application/pdf"],
7
+ excel: [
8
+ "application/vnd.ms-excel",
9
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
10
+ ],
11
+ word: [
12
+ "application/msword",
13
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
14
+ ],
15
+ all: ["*/*"]
16
+ };
17
+ return a.flatMap((l) => i[l] || []).join(",");
18
+ }
19
+ function p(e = {}) {
20
+ return new Promise((a) => {
21
+ const i = document.createElement("input");
22
+ i.type = "file", i.style.display = "none", e.multiple && e.maxFiles && e.maxFiles > 1 && (i.multiple = !0);
23
+ const l = s(e.accept);
24
+ l && (i.accept = l), i.addEventListener("change", (r) => {
25
+ const n = r.target;
26
+ let t = [];
27
+ if (n.files && n.files.length > 0 && (t = Array.from(n.files), e.maxFiles && t.length > e.maxFiles && (t = t.slice(0, e.maxFiles)), e.maxFileSize)) {
28
+ const m = o(e.maxFileSize);
29
+ t = t.filter((c) => c.size <= m);
30
+ }
31
+ a(t), document.body.removeChild(i);
32
+ }), document.body.appendChild(i), i.click();
33
+ });
34
+ }
35
+ export {
36
+ p as o
37
+ };
@@ -0,0 +1,30 @@
1
+ import { format, differenceInDays, isAfter } from 'date-fns'
2
+ import { ru } from 'date-fns/locale'
3
+
4
+ /**
5
+ * Форматирует дату в человекочитаемый вид: 20 июня 2025
6
+ */
7
+ export function formatDateReadable(date: string | Date): string {
8
+ return format(new Date(date), 'd MMMM yyyy', { locale: ru })
9
+ }
10
+
11
+ /**
12
+ * Форматирует дату для отображения времени: 20 июня, 14:30
13
+ */
14
+ export function formatDateWithTime(date: string | Date): string {
15
+ return format(new Date(date), 'd MMMM, HH:mm', { locale: ru })
16
+ }
17
+
18
+ /**
19
+ * Возвращает разницу между датами в днях
20
+ */
21
+ export function getDaysBetween(start: string | Date, end: string | Date): number {
22
+ return differenceInDays(new Date(end), new Date(start))
23
+ }
24
+
25
+ /**
26
+ * Проверяет, истекла ли дата
27
+ */
28
+ export function isExpired(date: string | Date): boolean {
29
+ return isAfter(new Date(), new Date(date))
30
+ }
@@ -0,0 +1,32 @@
1
+ import dayjs from 'dayjs'
2
+
3
+ // 📦 Плагины
4
+ import localizedFormat from 'dayjs/plugin/localizedFormat'
5
+ import relativeTime from 'dayjs/plugin/relativeTime'
6
+ import isToday from 'dayjs/plugin/isToday'
7
+ import isBetween from 'dayjs/plugin/isBetween'
8
+ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
9
+ import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
10
+ import duration from 'dayjs/plugin/duration'
11
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
12
+ import dayOfYear from 'dayjs/plugin/dayOfYear'
13
+
14
+ // 🌍 Локаль
15
+ import 'dayjs/locale/ru'
16
+
17
+ // 🧩 Установка плагинов
18
+ dayjs.extend(localizedFormat)
19
+ dayjs.extend(relativeTime)
20
+ dayjs.extend(isToday)
21
+ dayjs.extend(isBetween)
22
+ dayjs.extend(isSameOrBefore)
23
+ dayjs.extend(isSameOrAfter)
24
+ dayjs.extend(duration)
25
+ dayjs.extend(customParseFormat)
26
+ dayjs.extend(dayOfYear);
27
+
28
+ // 🗣️ Установка локали
29
+ dayjs.locale('ru')
30
+
31
+ // 📤 Экспорт по умолчанию
32
+ export {dayjs}
@@ -0,0 +1,43 @@
1
+ export type Handler<T> = (event: T) => void;
2
+
3
+ export interface TypedEventBus<Events extends Record<string, any>> {
4
+ on<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
5
+ off<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
6
+ emit<K extends keyof Events>(type: K, evt?: Events[K]): void;
7
+ clear(): void;
8
+ }
9
+
10
+
11
+
12
+ export function EventBus<Events extends Record<string, any>>(): TypedEventBus<Events> {
13
+ const allHandlers = new Map<keyof Events, Handler<any>[]>();
14
+
15
+ return {
16
+ on<K extends keyof Events>(type: K, handler: Handler<Events[K]>) {
17
+ const handlers = allHandlers.get(type) || [];
18
+ handlers.push(handler);
19
+ allHandlers.set(type, handlers);
20
+ },
21
+
22
+ off<K extends keyof Events>(type: K, handler: Handler<Events[K]>) {
23
+ const handlers = allHandlers.get(type);
24
+ if (handlers) {
25
+ allHandlers.set(
26
+ type,
27
+ handlers.filter(h => h !== handler)
28
+ );
29
+ }
30
+ },
31
+
32
+ emit<K extends keyof Events>(type: K, evt?: Events[K]) {
33
+ const handlers = allHandlers.get(type);
34
+ if (handlers) {
35
+ handlers.forEach(handler => handler(evt));
36
+ }
37
+ },
38
+
39
+ clear() {
40
+ allHandlers.clear();
41
+ }
42
+ };
43
+ }