adata-ui 2.1.40-beta.18 → 2.1.40-beta.19

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 (211) hide show
  1. package/.playground/app.vue +102 -0
  2. package/assets/styles/index.scss +67 -5
  3. package/components/elements/a-select-row/ASelectRowV2.vue +214 -0
  4. package/components/elements/a-select-row/index.vue +3 -5
  5. package/components/elements/accordion/AAccordion.vue +5 -3
  6. package/components/elements/accordion/AAccordionGroup/AAccordionGroup.vue +3 -3
  7. package/components/elements/alert/AAlert.vue +34 -47
  8. package/components/elements/bg-block/ABgBlock.vue +1 -1
  9. package/components/elements/button/AButton.vue +3 -3
  10. package/components/elements/button/AButtonV2.vue +133 -0
  11. package/components/elements/button-login/index.vue +6 -10
  12. package/components/elements/chip-wrapper/AChipWrapper.vue +1 -1
  13. package/components/elements/chips/AChips.vue +2 -2
  14. package/components/elements/companies/AOurClients.vue +3 -1
  15. package/components/elements/curve-block-v2/ACurveBlockV2.vue +85 -0
  16. package/components/elements/digit-badge/ADigitBadge.vue +24 -22
  17. package/components/elements/feature-description/AFeatureDescription.vue +1 -1
  18. package/components/elements/leave-note/ALeaveNote.vue +39 -18
  19. package/components/elements/pagination/APagination.vue +7 -7
  20. package/components/elements/segmented/ASegmentedV2.vue +151 -0
  21. package/components/elements/select/ASelect.vue +4 -4
  22. package/components/elements/select/ASelectMobile.vue +2 -2
  23. package/components/elements/select/ASelectV2.vue +588 -0
  24. package/components/elements/select/ui/select-button.vue +1 -1
  25. package/components/elements/show-more/AShowMoreV2.vue +26 -0
  26. package/components/elements/slider/ASlider.vue +174 -0
  27. package/components/elements/slider/ASliderItem.vue +31 -0
  28. package/components/elements/slider/types.ts +21 -0
  29. package/components/elements/star-rating/AStarRating.vue +12 -4
  30. package/components/elements/status-badge/AStatusBadge.vue +91 -44
  31. package/components/elements/step-slider/AStepSliderColCard.vue +232 -0
  32. package/components/elements/step-slider/AStepSliderColNumber.vue +178 -0
  33. package/components/elements/table/ATable.vue +1 -1
  34. package/components/elements/table/table.config.ts +2 -2
  35. package/components/elements/tree-select/ATreeSelect.vue +97 -113
  36. package/components/elements/tree-select/TreeService.ts +142 -207
  37. package/components/elements/tree-select/components/ATreeSelectNode.vue +104 -0
  38. package/components/elements/tree-select/types.ts +40 -11
  39. package/components/elements/tree-select/utils.ts +30 -0
  40. package/components/elements/tree-select-modal/ATreeSelectModal.vue +217 -0
  41. package/components/features/color-mode/AColorMode.client.vue +74 -32
  42. package/components/features/dropdown/ADropdownV2.vue +140 -0
  43. package/components/features/lang-switcher/lang-switcher.vue +125 -40
  44. package/components/features/payment/banner/BasicPlusLimitBanner.vue +3 -3
  45. package/components/features/payment/banner/PaymentBanner.vue +3 -3
  46. package/components/features/payment/banner/UpSellBanner.vue +3 -3
  47. package/components/features/payment/process/PaymentKaspiQrSidePanel.vue +45 -27
  48. package/components/features/payment/process/PaymentKaspiRedirectSidePanel.vue +34 -23
  49. package/components/features/payment/process/PaymentMethodSidePanel.vue +66 -49
  50. package/components/features/payment/process/PaymentProcess.vue +6 -6
  51. package/components/features/payment/process/PaymentTopUpSidePanel.vue +49 -63
  52. package/components/features/pk-mobile-services/APkMobileServices.vue +6 -28
  53. package/components/features//321/201hange-version/AChangeVersion.vue +2 -2
  54. package/components/forms/checkbox/ACheckbox.vue +1 -1
  55. package/components/forms/checkbox/ACheckboxV2.vue +229 -0
  56. package/components/forms/feedback-form/FeedbackForm.vue +8 -8
  57. package/components/forms/feedback-form/FeedbackFormV2.vue +182 -0
  58. package/components/forms/input/AInputV2.vue +542 -0
  59. package/components/forms/input/date/AInputDate.vue +2 -2
  60. package/components/forms/input/password/AInputPassword.vue +8 -2
  61. package/components/forms/input/standard/AInputStandard.vue +3 -3
  62. package/components/forms/input/textarea/ATextarea.vue +2 -2
  63. package/components/forms/input/textarea/ATextareaV2.vue +248 -0
  64. package/components/forms/toggle/AToggle.vue +2 -3
  65. package/components/forms/toggle/AToggleV2.vue +71 -0
  66. package/components/modals/AnotherDeviceModal.vue +22 -18
  67. package/components/modals/ApplicationAcceptedModal.vue +12 -15
  68. package/components/modals/ConnectingTariffModal.vue +13 -20
  69. package/components/modals/ContactsMobileModel.vue +1 -1
  70. package/components/modals/ContentNavigationModal.vue +77 -333
  71. package/components/modals/Insufficient-funds-modal.vue +18 -33
  72. package/components/modals/LimitReachedModal.vue +17 -14
  73. package/components/modals/NoAccessModal.vue +9 -11
  74. package/components/modals/PaymentMethodModal.vue +1 -1
  75. package/components/modals/ReportBugConfirmModal.vue +12 -10
  76. package/components/modals/ReportBugModal.vue +46 -38
  77. package/components/modals/Resend.vue +9 -10
  78. package/components/modals/SubmitApplicationModal.vue +27 -24
  79. package/components/modals/id/IdBanner.vue +3 -3
  80. package/components/modals/id/IdConfirmAccountOtpModal.vue +4 -9
  81. package/components/modals/id/IdLoginModal.vue +3 -8
  82. package/components/modals/id/IdModals.vue +23 -10
  83. package/components/modals/id/IdRecoveryModal.vue +1 -1
  84. package/components/modals/id/IdTwoFactorModal.vue +3 -8
  85. package/components/navigation/bottom-navigation/ABottomNavigation.vue +1 -1
  86. package/components/navigation/breadcrumbs/ABreadcrumbs.vue +106 -45
  87. package/components/navigation/breadcrumbs/types.ts +3 -0
  88. package/components/navigation/footer/AFooter.vue +39 -40
  89. package/components/navigation/footer/ui/a-footer-accordion.vue +9 -9
  90. package/components/navigation/header/AHeader.vue +68 -51
  91. package/components/navigation/header/AlmatyContacts.vue +78 -78
  92. package/components/navigation/header/CardGallery.vue +9 -7
  93. package/components/navigation/header/ContactMenu.vue +26 -92
  94. package/components/navigation/header/HeaderLink.vue +181 -213
  95. package/components/navigation/header/HeaderUsage.vue +139 -0
  96. package/components/navigation/header/ListItem.vue +2 -2
  97. package/components/navigation/header/NavCard.vue +1 -1
  98. package/components/navigation/header/NavList.vue +33 -92
  99. package/components/navigation/header/NotificationsMenu.vue +2 -3
  100. package/components/navigation/header/ProductMenu.vue +81 -127
  101. package/components/navigation/header/ProfileMenu.vue +122 -151
  102. package/components/navigation/header/SystemNotification.vue +108 -0
  103. package/components/navigation/mobile-navigation/AMobileNavigation.vue +23 -15
  104. package/components/navigation/pill-tabs/APillTabs.vue +2 -2
  105. package/components/navigation/pill-tabs/APillTabsV2.vue +226 -0
  106. package/components/overlays/drawer/ADrawerV2.vue +335 -0
  107. package/components/overlays/modal/AModal.vue +4 -4
  108. package/components/overlays/modal/AModalV2.vue +397 -0
  109. package/components/overlays/side-panel/ASidePanel.vue +10 -7
  110. package/components/overlays/sideover/ASlideover.vue +6 -6
  111. package/components/overlays/tooltip/ATooltip.vue +1 -1
  112. package/components/overlays/tooltip/ATooltipV2.vue +223 -0
  113. package/components/overlays/tooltip/types.ts +26 -0
  114. package/components/overlays/tooltip/useTooltipTrigger.ts +101 -0
  115. package/components/transitions/ATransitionHeight.vue +1 -1
  116. package/composables/useAccessTokenCookie.ts +25 -0
  117. package/composables/useActiveNavigation.ts +84 -0
  118. package/composables/useChipOverflow.ts +92 -0
  119. package/composables/useHeaderNavigationLinks.ts +140 -98
  120. package/icons/archive.vue +16 -0
  121. package/icons/arrow/arrow-left-right.vue +8 -0
  122. package/icons/arrow/arrow-right.vue +14 -0
  123. package/icons/arrow/arrows-in.vue +11 -0
  124. package/icons/arrow/arrows-out.vue +11 -0
  125. package/icons/arrow/arrows-resize-in.vue +38 -0
  126. package/icons/arrow/arrows-resize-out.vue +17 -0
  127. package/icons/bill.vue +3 -0
  128. package/icons/bot.vue +52 -0
  129. package/icons/briefcase.vue +14 -0
  130. package/icons/building.vue +9 -0
  131. package/icons/car-side.vue +16 -0
  132. package/icons/cart.vue +15 -0
  133. package/icons/chart-no-axes-column.vue +3 -0
  134. package/icons/clock-time.vue +24 -0
  135. package/icons/cloud/cloud-upload.vue +3 -0
  136. package/icons/code.vue +9 -0
  137. package/icons/compare-outlined.vue +8 -0
  138. package/icons/dots-horizontal.vue +31 -0
  139. package/icons/download-line.vue +13 -0
  140. package/icons/download-rounded.vue +15 -0
  141. package/icons/egov.vue +41 -0
  142. package/icons/elicense.vue +38 -0
  143. package/icons/favourite-bookmark-outline.vue +17 -0
  144. package/icons/file/file-check-corner.vue +3 -0
  145. package/icons/file/file-spreadsheet.vue +3 -0
  146. package/icons/file-pen.vue +31 -0
  147. package/icons/file-stack.vue +31 -0
  148. package/icons/file-types/excel.vue +131 -0
  149. package/icons/file-types/html.vue +13 -0
  150. package/icons/file-types/jpeg.vue +16 -0
  151. package/icons/file-types/pdf.vue +11 -0
  152. package/icons/file-types/png.vue +11 -0
  153. package/icons/file-types/rar.vue +11 -0
  154. package/icons/file-types/word.vue +50 -0
  155. package/icons/file-types/zip.vue +11 -0
  156. package/icons/gauge.vue +17 -0
  157. package/icons/git-compare.vue +38 -0
  158. package/icons/git-fork.vue +3 -0
  159. package/icons/graduation-cap.vue +31 -0
  160. package/icons/graph-loading.vue +34 -0
  161. package/icons/headset.vue +6 -0
  162. package/icons/help-question-circle.vue +26 -0
  163. package/icons/in-row-type.vue +46 -0
  164. package/icons/in-table-type.vue +29 -0
  165. package/icons/landmark.vue +3 -0
  166. package/icons/layers.vue +3 -0
  167. package/icons/letter/letter-a.vue +6 -0
  168. package/icons/letter/letter-b.vue +6 -0
  169. package/icons/letter/letter-c.vue +6 -0
  170. package/icons/letter/letter-d.vue +6 -0
  171. package/icons/letter/letter-e.vue +6 -0
  172. package/icons/link-url.vue +3 -0
  173. package/icons/list-tree.vue +3 -0
  174. package/icons/mail-question-mark.vue +8 -0
  175. package/icons/message/message-square.vue +3 -0
  176. package/icons/message-dotted.vue +30 -0
  177. package/icons/network.vue +3 -0
  178. package/icons/newspaper.vue +3 -0
  179. package/icons/notification-error.vue +17 -0
  180. package/icons/person.vue +22 -0
  181. package/icons/phone-call.vue +6 -0
  182. package/icons/phone-reversed.vue +3 -0
  183. package/icons/route.vue +7 -0
  184. package/icons/scan-search.vue +3 -0
  185. package/icons/settings.vue +26 -0
  186. package/icons/shield-alert.vue +31 -0
  187. package/icons/shield-verified.vue +14 -0
  188. package/icons/socials/facebook-color.vue +16 -0
  189. package/icons/socials/globe-color.vue +16 -0
  190. package/icons/socials/instagram-color.vue +46 -0
  191. package/icons/socials/linkedin-color.vue +14 -0
  192. package/icons/socials/telegram-color.vue +16 -0
  193. package/icons/socials/tiktok-color.vue +14 -0
  194. package/icons/socials/vk-color.vue +16 -0
  195. package/icons/socials/youtube-color.vue +16 -0
  196. package/icons/sparkles.vue +3 -0
  197. package/icons/sun.vue +13 -3
  198. package/icons/users-round.vue +3 -0
  199. package/icons/view-eye-open.vue +13 -0
  200. package/icons/workflow.vue +3 -0
  201. package/icons/zap.vue +3 -0
  202. package/lang/en.ts +49 -5
  203. package/lang/kk.ts +50 -6
  204. package/lang/ru.ts +51 -7
  205. package/package.json +1 -1
  206. package/plugins/toast.client.ts +38 -55
  207. package/shared/constans/pages.ts +8 -2
  208. package/tailwind.config.ts +147 -116
  209. package/utils/twMerge.ts +34 -0
  210. package/components/elements/tree-select/components/tree-select-nodes.vue +0 -91
  211. package/components/navigation/header/TopHeader.vue +0 -196
@@ -0,0 +1,397 @@
1
+ <script setup lang="ts">
2
+ import { onKeyStroke, useScrollLock, useWindowSize } from '@vueuse/core'
3
+
4
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'container' | 'fullscreen'
5
+
6
+ const props = withDefaults(defineProps<{
7
+ title?: string
8
+ size?: ModalSize
9
+ width?: string
10
+ closeOnOverlay?: boolean
11
+ closeOnEsc?: boolean
12
+ lockScroll?: boolean
13
+ persistent?: boolean
14
+ transition?: boolean
15
+ contentClass?: string
16
+ hideHeader?: boolean
17
+ hideClose?: boolean
18
+ blur?: boolean | 'sm' | 'md' | 'lg' | 'xl'
19
+ mobileSheet?: boolean
20
+ swipeToClose?: boolean
21
+ swipeThreshold?: number
22
+ showDragHandle?: boolean
23
+ dataTestId?: string
24
+ iconXMarkTestId?: string
25
+ }>(), {
26
+ size: 'md',
27
+ closeOnOverlay: true,
28
+ closeOnEsc: true,
29
+ lockScroll: true,
30
+ persistent: false,
31
+ transition: true,
32
+ hideHeader: false,
33
+ hideClose: false,
34
+ blur: false,
35
+ mobileSheet: true,
36
+ swipeToClose: true,
37
+ swipeThreshold: 65,
38
+ showDragHandle: true,
39
+ dataTestId: undefined,
40
+ iconXMarkTestId: undefined,
41
+ })
42
+
43
+ const emit = defineEmits<{
44
+ (e: 'close'): void
45
+ (e: 'open'): void
46
+ }>()
47
+
48
+ const open = defineModel<boolean>({ required: true })
49
+
50
+ const contentRef = ref<HTMLElement | null>(null)
51
+ const overlayRef = ref<HTMLElement | null>(null)
52
+ const swipeClosing = ref(false)
53
+ const bodyScrollLocked = useScrollLock(import.meta.client ? document.body : null)
54
+ const { width: windowWidth } = useWindowSize()
55
+
56
+ const isMobile = computed(() => windowWidth.value < 1025)
57
+ const isSheet = computed(() => isMobile.value && props.mobileSheet)
58
+
59
+ const sizeStyle = computed(() => {
60
+ if (isSheet.value) return { width: '100%' }
61
+ if (props.width) return { width: props.width }
62
+
63
+ switch (props.size) {
64
+ case 'sm': return { width: '380px' }
65
+ case 'md': return { width: '520px' }
66
+ case 'lg': return { width: '720px' }
67
+ case 'xl': return { width: '1100px' }
68
+ case 'container': return {}
69
+ case 'fullscreen': return { width: '100vw', height: '100vh' }
70
+ default: return { width: '520px' }
71
+ }
72
+ })
73
+
74
+ const blurClass = computed(() => {
75
+ if (!props.blur) return ''
76
+
77
+ switch (props.blur) {
78
+ case 'sm': return 'backdrop-blur-sm'
79
+ case 'md': return 'backdrop-blur-md'
80
+ case 'lg': return 'backdrop-blur-lg'
81
+ case 'xl': return 'backdrop-blur-xl'
82
+ default: return 'backdrop-blur'
83
+ }
84
+ })
85
+
86
+ const overlayClass = computed(() => {
87
+ const base = ['modal-v2-overlay fixed inset-0 z-[10000] flex bg-black/40 dark:bg-black/60']
88
+
89
+ if (isSheet.value) {
90
+ base.push('items-end justify-stretch')
91
+ }
92
+ else {
93
+ base.push(props.size === 'container' ? 'items-center justify-center' : 'items-center justify-center p-4')
94
+ }
95
+
96
+ if (blurClass.value) base.push(blurClass.value)
97
+
98
+ return base.join(' ')
99
+ })
100
+
101
+ const contentBaseClass = computed(() => {
102
+ const base = ['modal-v2-content flex flex-col overflow-hidden border bg-white shadow-2xl dark:bg-gray-900']
103
+
104
+ if (isSheet.value) {
105
+ base.push('w-full max-w-none max-h-[100dvh] rounded-t-xl rounded-b-none border-x-0 border-b-0 border-t border-gray-200 dark:border-gray-800')
106
+ }
107
+ else {
108
+ const radius = props.size === 'fullscreen' ? 'rounded-none' : 'rounded-xl'
109
+ const widthCls = props.size === 'container'
110
+ ? ' w-full max-w-screen-sm md:max-w-screen-md lg:max-w-screen-lg xl:max-w-screen-xl 2xl:max-w-screen-2xl'
111
+ : ''
112
+ base.push(`max-h-[calc(100vh-2rem)] border-gray-200 dark:border-gray-800 ${radius}${widthCls}`)
113
+ }
114
+
115
+ return base.join(' ')
116
+ })
117
+
118
+ const overlayTransitionName = computed(() => {
119
+ if (swipeClosing.value) return ''
120
+ return props.transition ? 'modal-v2-overlay' : ''
121
+ })
122
+ const contentTransitionName = computed(() => {
123
+ if (swipeClosing.value || !props.transition) return ''
124
+ return isSheet.value ? 'modal-v2-sheet' : 'modal-v2-content'
125
+ })
126
+
127
+ function closeIfAllowed() {
128
+ if (props.persistent) return
129
+ open.value = false
130
+ }
131
+
132
+ function onOverlayClick(event: MouseEvent) {
133
+ if (!props.closeOnOverlay || props.persistent) return
134
+ if (event.target === event.currentTarget) {
135
+ open.value = false
136
+ }
137
+ }
138
+
139
+ onKeyStroke('Escape', () => {
140
+ if (!open.value) return
141
+ if (!props.closeOnEsc || props.persistent) return
142
+ open.value = false
143
+ })
144
+
145
+ function setScrollbarCompensation(active: boolean) {
146
+ if (!import.meta.client) return
147
+
148
+ if (active) {
149
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
150
+ document.body.style.paddingRight = scrollbarWidth > 0 ? `${scrollbarWidth}px` : ''
151
+ }
152
+ else {
153
+ document.body.style.paddingRight = ''
154
+ }
155
+ }
156
+
157
+ watch(open, (value) => {
158
+ if (props.lockScroll) {
159
+ if (value) setScrollbarCompensation(true)
160
+ bodyScrollLocked.value = value
161
+ if (!value) setScrollbarCompensation(false)
162
+ }
163
+
164
+ if (value) emit('open')
165
+ else emit('close')
166
+ })
167
+
168
+ onBeforeUnmount(() => {
169
+ if (bodyScrollLocked.value) {
170
+ bodyScrollLocked.value = false
171
+ }
172
+ setScrollbarCompensation(false)
173
+ })
174
+
175
+ const dragging = ref(false)
176
+ const dragStartY = ref(0)
177
+ const dragDelta = ref(0)
178
+
179
+ function canSwipe() {
180
+ return isSheet.value && props.swipeToClose && !props.persistent
181
+ }
182
+
183
+ function setTransform(value: string) {
184
+ if (contentRef.value) {
185
+ contentRef.value.style.transform = value
186
+ }
187
+ }
188
+
189
+ function onTouchStart(event: TouchEvent) {
190
+ if (!canSwipe()) return
191
+ dragging.value = true
192
+ dragStartY.value = event.touches[0].clientY
193
+ dragDelta.value = 0
194
+
195
+ if (contentRef.value) {
196
+ contentRef.value.style.transition = 'none'
197
+ }
198
+ }
199
+
200
+ function onTouchMove(event: TouchEvent) {
201
+ if (!dragging.value || !canSwipe()) return
202
+
203
+ const delta = event.touches[0].clientY - dragStartY.value
204
+ if (delta < 0) {
205
+ dragDelta.value = 0
206
+ setTransform('')
207
+ return
208
+ }
209
+
210
+ dragDelta.value = delta
211
+ setTransform(`translateY(${delta}px)`)
212
+ }
213
+
214
+ function prefersReducedMotion() {
215
+ return import.meta.client && window.matchMedia('(prefers-reduced-motion: reduce)').matches
216
+ }
217
+
218
+ function animateClose() {
219
+ const content = contentRef.value
220
+
221
+ if (!content || prefersReducedMotion()) {
222
+ open.value = false
223
+ return
224
+ }
225
+
226
+ swipeClosing.value = true
227
+
228
+ let done = false
229
+ const finish = () => {
230
+ if (done) return
231
+ done = true
232
+ content.removeEventListener('transitionend', onTransitionEnd)
233
+ open.value = false
234
+ swipeClosing.value = false
235
+ }
236
+
237
+ function onTransitionEnd(event: TransitionEvent) {
238
+ if (event.target === content && event.propertyName === 'transform') {
239
+ finish()
240
+ }
241
+ }
242
+
243
+ content.addEventListener('transitionend', onTransitionEnd)
244
+ setTimeout(finish, 320)
245
+
246
+ requestAnimationFrame(() => {
247
+ content.style.transition = 'transform 260ms cubic-bezier(0.22, 1, 0.36, 1)'
248
+ content.style.transform = 'translateY(100%)'
249
+
250
+ if (overlayRef.value) {
251
+ overlayRef.value.style.transition = 'opacity 260ms ease'
252
+ overlayRef.value.style.opacity = '0'
253
+ }
254
+ })
255
+ }
256
+
257
+ function onTouchEnd() {
258
+ if (!dragging.value) return
259
+ dragging.value = false
260
+
261
+ const shouldClose = dragDelta.value > props.swipeThreshold && canSwipe()
262
+
263
+ if (shouldClose) {
264
+ animateClose()
265
+ }
266
+ else {
267
+ if (contentRef.value) {
268
+ contentRef.value.style.transition = 'transform 220ms cubic-bezier(0.22, 1, 0.36, 1)'
269
+ contentRef.value.style.transform = ''
270
+ }
271
+ }
272
+
273
+ dragDelta.value = 0
274
+ }
275
+ </script>
276
+
277
+ <template>
278
+ <client-only>
279
+ <teleport to="body">
280
+ <transition :name="overlayTransitionName">
281
+ <div
282
+ v-if="open"
283
+ ref="overlayRef"
284
+ :class="overlayClass"
285
+ @mousedown="onOverlayClick"
286
+ >
287
+ <transition :name="contentTransitionName" appear>
288
+ <div
289
+ v-if="open"
290
+ ref="contentRef"
291
+ :class="contentBaseClass"
292
+ :style="sizeStyle"
293
+ :data-test-id="dataTestId"
294
+ @mousedown.stop
295
+ >
296
+ <div
297
+ v-if="isSheet && showDragHandle"
298
+ class="flex shrink-0 cursor-grab touch-none justify-center py-2"
299
+ @touchstart.passive="onTouchStart"
300
+ @touchmove="onTouchMove"
301
+ @touchend="onTouchEnd"
302
+ @touchcancel="onTouchEnd"
303
+ >
304
+ <div class="h-1 w-10 rounded-full bg-gray-300 dark:bg-gray-600" />
305
+ </div>
306
+
307
+ <header
308
+ v-if="!hideHeader"
309
+ class="flex shrink-0 items-center justify-between gap-3 border-b border-gray-200 px-5 py-4 dark:border-gray-800"
310
+ @touchstart.passive="onTouchStart"
311
+ @touchmove="onTouchMove"
312
+ @touchend="onTouchEnd"
313
+ @touchcancel="onTouchEnd"
314
+ >
315
+ <slot name="header">
316
+ <h2 v-if="title" class="text-h5 text-gray-900 dark:text-gray-100">
317
+ {{ title }}
318
+ </h2>
319
+ </slot>
320
+ <button
321
+ v-if="!hideClose"
322
+ type="button"
323
+ class="ml-auto rounded-sm p-1 transition hover:bg-gray-100 dark:hover:bg-gray-800 dark:hover:text-gray-200"
324
+ :data-test-id="iconXMarkTestId"
325
+ @click="closeIfAllowed"
326
+ >
327
+ <a-icon-x-mark class="size-4" />
328
+ </button>
329
+ </header>
330
+
331
+ <div class="min-h-0 flex-1 overflow-auto" :class="contentClass">
332
+ <slot :close="closeIfAllowed" />
333
+ </div>
334
+
335
+ <footer
336
+ v-if="$slots.footer"
337
+ class="shrink-0 border-t border-gray-200 px-5 py-4 dark:border-gray-800"
338
+ >
339
+ <slot name="footer" :close="closeIfAllowed" />
340
+ </footer>
341
+ </div>
342
+ </transition>
343
+ </div>
344
+ </transition>
345
+ </teleport>
346
+ </client-only>
347
+ </template>
348
+
349
+ <style scoped lang="scss">
350
+ .modal-v2-overlay-enter-active {
351
+ transition: opacity 200ms ease-out;
352
+ }
353
+
354
+ .modal-v2-overlay-leave-active {
355
+ transition: opacity 150ms ease-in;
356
+ }
357
+
358
+ .modal-v2-overlay-enter-from,
359
+ .modal-v2-overlay-leave-to {
360
+ opacity: 0;
361
+ }
362
+
363
+ .modal-v2-content-enter-active {
364
+ transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1), opacity 220ms ease-out;
365
+ }
366
+
367
+ .modal-v2-content-leave-active {
368
+ transition: transform 150ms ease-in, opacity 150ms ease-in;
369
+ }
370
+
371
+ .modal-v2-content-enter-from,
372
+ .modal-v2-content-leave-to {
373
+ opacity: 0;
374
+ transform: translateY(8px) scale(0.98);
375
+ }
376
+
377
+ .modal-v2-sheet-enter-active,
378
+ .modal-v2-sheet-leave-active {
379
+ transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
380
+ }
381
+
382
+ .modal-v2-sheet-enter-from,
383
+ .modal-v2-sheet-leave-to {
384
+ transform: translateY(100%);
385
+ }
386
+
387
+ @media (prefers-reduced-motion: reduce) {
388
+ .modal-v2-overlay-enter-active,
389
+ .modal-v2-overlay-leave-active,
390
+ .modal-v2-content-enter-active,
391
+ .modal-v2-content-leave-active,
392
+ .modal-v2-sheet-enter-active,
393
+ .modal-v2-sheet-leave-active {
394
+ transition: none;
395
+ }
396
+ }
397
+ </style>
@@ -24,6 +24,7 @@ const props = withDefaults(defineProps<{
24
24
  headerClass?: string
25
25
  bodyClass?: string
26
26
  footerClass?: string
27
+ dataTestId?: string
27
28
  }>(), {
28
29
  idName: "vsp-container",
29
30
  side: "right",
@@ -36,7 +37,8 @@ const props = withDefaults(defineProps<{
36
37
  overlayOpacity: 0.5,
37
38
  overlayDuration: 500,
38
39
  panelColor: "bg-white dark:bg-gray-900",
39
- panelDuration: 300
40
+ panelDuration: 300,
41
+ dataTestId: undefined,
40
42
  })
41
43
 
42
44
  defineEmits<{
@@ -128,10 +130,10 @@ watch(() => [modelValue.value, panel.value], (newP, oldP) => {
128
130
 
129
131
  const roundedClass = computed(() => {
130
132
  const classes = {
131
- left: "rounded-r-xl",
132
- right: "rounded-l-xl",
133
- top: "rounded-b-xl",
134
- bottom: "rounded-t-xl",
133
+ left: "rounded-r-lg",
134
+ right: "rounded-l-lg",
135
+ top: "rounded-b-lg",
136
+ bottom: "rounded-t-lg",
135
137
  }
136
138
 
137
139
  return classes[panelSide.value]
@@ -170,7 +172,7 @@ const modalHeight = ref(0)
170
172
  const touchstart = (event: TouchEvent) => {
171
173
  isClose.value = false
172
174
  positionStart.value = event.touches[0].clientY
173
- modalHeight.value = panel.value?.offsetHeight || 0 // Запоминаем текущую высоту модалки
175
+ modalHeight.value = panel.value?.offsetHeight || 0
174
176
  }
175
177
 
176
178
  const touchmove = (event: TouchEvent) => {
@@ -179,7 +181,7 @@ const touchmove = (event: TouchEvent) => {
179
181
  const touchPosition = event.touches[0].clientY
180
182
  const step = touchPosition - positionStart.value
181
183
 
182
- if (step < 0) return // предотвратить движение вверх
184
+ if (step < 0) return
183
185
 
184
186
  const newHeight = modalHeight.value - step
185
187
  panel.value.style.height = `${newHeight}px`
@@ -219,6 +221,7 @@ const touchend = () => {
219
221
  class="vsp fixed flex flex-col"
220
222
  :class="[`vsp--${panelSide}-side`, $attrs.class, roundedClass, panelColor]"
221
223
  :style="panelStyles"
224
+ :data-test-id="dataTestId"
222
225
  >
223
226
  <div
224
227
  class="w-full flex justify-center items-center mt-1 lg:hidden"
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
 
3
- import { twJoin, twMerge } from 'tailwind-merge'
3
+ import { twJoin, twMerge } from '#adata-ui/utils/twMerge'
4
4
  import { onClickOutside, useWindowSize } from '@vueuse/core'
5
5
  import {disableBodyScroll, enableBodyScroll} from "body-scroll-lock";
6
6
 
@@ -37,10 +37,10 @@ const uiConfig = {
37
37
  bottom: 'bottom-0 left-0 w-full'
38
38
  },
39
39
  rounded: {
40
- top: 'rounded-b-lg',
41
- bottom: 'rounded-t-lg',
42
- left: 'rounded-r-lg',
43
- right: 'rounded-l-lg'
40
+ top: 'rounded-b-md',
41
+ bottom: 'rounded-t-md',
42
+ left: 'rounded-r-md',
43
+ right: 'rounded-l-md'
44
44
  },
45
45
  fullscreen: 'w-screen h-screen rounded-none',
46
46
  transition: {
@@ -219,7 +219,7 @@ const modalHeight = ref(0)
219
219
  const touchstart = (event: TouchEvent) => {
220
220
  isClose.value = false
221
221
  positionStart.value = event.touches[0].clientY
222
- modalHeight.value = slideover.value?.offsetHeight || 0 // Запоминаем текущую высоту модалки
222
+ modalHeight.value = slideover.value?.offsetHeight || 0
223
223
  }
224
224
 
225
225
  const touchmove = (event: TouchEvent) => {
@@ -56,7 +56,7 @@ const baseClass = computed(() => {
56
56
  const color = props.errorParsing ? 'text-[#E74135] dark:text-[#F47E75]' : 'text-white dark:text-deepblue-900'
57
57
  const pad = props.size === 'sm' ? 'px-4 py-2' : 'px-4 py-4'
58
58
  const truncated = props.truncate ? 'truncate' : 'max-w-[530px] w-max'
59
- return ['text-xs font-normal absolute', bg, color, 'rounded-md', pad, truncated].join(' ')
59
+ return ['text-body-sm font-normal absolute', bg, color, 'rounded-sm', pad, truncated].join(' ')
60
60
  })
61
61
 
62
62
  /* --- positioning logic --- */