bfg-common 1.5.451 → 1.5.452

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.
@@ -0,0 +1,360 @@
1
+ <template>
2
+ <div
3
+ class="window-container"
4
+ :style="{
5
+ left: x + 'px',
6
+ top: y + 'px',
7
+ width: width + 'px',
8
+ height: height + 'px',
9
+ }"
10
+ >
11
+ <div ref="headerEl" class="window-header">
12
+ <div class="window-title">{{ props.title }}</div>
13
+ <button class="window-close" @click="onHide">
14
+ <ui-icon name="close" class="close-icon" />
15
+ </button>
16
+ </div>
17
+
18
+ <div class="window-content">
19
+ <slot></slot>
20
+ <div
21
+ v-show="isShowContentBlocker"
22
+ :style="{}"
23
+ class="content-blocker"
24
+ ></div>
25
+ </div>
26
+
27
+ <!-- Ручки для ресайза -->
28
+ <div
29
+ class="resize-handle resize-top"
30
+ @mousedown="startResize($event, 'top')"
31
+ ></div>
32
+ <div
33
+ class="resize-handle resize-right"
34
+ @mousedown="startResize($event, 'right')"
35
+ ></div>
36
+ <div
37
+ class="resize-handle resize-bottom"
38
+ @mousedown="startResize($event, 'bottom')"
39
+ ></div>
40
+ <div
41
+ class="resize-handle resize-left"
42
+ @mousedown="startResize($event, 'left')"
43
+ ></div>
44
+ <div
45
+ class="resize-handle resize-top-left"
46
+ @mousedown="startResize($event, 'top-left')"
47
+ ></div>
48
+ <div
49
+ class="resize-handle resize-top-right"
50
+ @mousedown="startResize($event, 'top-right')"
51
+ ></div>
52
+ <div
53
+ class="resize-handle resize-bottom-left"
54
+ @mousedown="startResize($event, 'bottom-left')"
55
+ ></div>
56
+ <div
57
+ class="resize-handle resize-bottom-right"
58
+ @mousedown="startResize($event, 'bottom-right')"
59
+ ></div>
60
+ </div>
61
+ </template>
62
+
63
+ <script setup lang="ts">
64
+ import { useDraggable } from '@vueuse/core'
65
+
66
+ const props = defineProps<{
67
+ top: number
68
+ left: number
69
+ width: number
70
+ height: number
71
+ title: string
72
+ }>()
73
+ const emits = defineEmits<{
74
+ (event: 'hide'): void
75
+ }>()
76
+
77
+ const headerEl = ref(null)
78
+ const isShowContentBlocker = ref<boolean>(false)
79
+
80
+ const x = ref(props.left)
81
+ const y = ref(props.top)
82
+ const width = ref(props.width)
83
+ const height = ref(props.height)
84
+
85
+ // Используем vueuse для перетаскивания
86
+ useDraggable(headerEl, {
87
+ initialValue: { x: props.left, y: props.top },
88
+ onMove({ x: newX, y: newY }) {
89
+ x.value = newX
90
+ y.value = newY
91
+ },
92
+ onStart() {
93
+ isShowContentBlocker.value = true
94
+ },
95
+ onEnd() {
96
+ isShowContentBlocker.value = false
97
+ fixPosition()
98
+ },
99
+ })
100
+
101
+ const fixSize = (): void => {
102
+ const globalWindowWidth = window.innerWidth
103
+ const globalWindowHeight = window.innerHeight
104
+
105
+ width.value = Math.min(globalWindowWidth - 8 * 2, width.value)
106
+ height.value = Math.min(globalWindowHeight - 8 * 2, height.value)
107
+ }
108
+ const fixPosition = (): void => {
109
+ const globalWindowWidth = window.innerWidth
110
+ const globalWindowHeight = window.innerHeight
111
+ let newX = x.value
112
+ let newY = y.value
113
+ if (x.value + width.value / 2 > globalWindowWidth) {
114
+ newX = globalWindowWidth - 20
115
+ } else if (x.value + width.value > globalWindowWidth - 8) {
116
+ newX = globalWindowWidth - width.value - 8
117
+ } else if (x.value < 8) {
118
+ newX = 8
119
+ }
120
+
121
+ if (y.value + height.value / 2 > globalWindowHeight) {
122
+ newY = globalWindowHeight - 20
123
+ } else if (y.value + height.value > globalWindowHeight - 8) {
124
+ newY = globalWindowHeight - height.value - 8
125
+ } else if (y.value < 8) {
126
+ newY = 8
127
+ }
128
+
129
+ smoothMove(newX, newY)
130
+ }
131
+ const smoothMove = (newX: number, newY: number, duration = 100): void => {
132
+ const startX = x.value
133
+ const startY = y.value
134
+
135
+ // Время начала анимации
136
+ const startTime = performance.now()
137
+
138
+ // Функция анимации
139
+ const animate = (currentTime: number): void => {
140
+ // Прошедшее время с начала анимации
141
+ const elapsedTime = currentTime - startTime
142
+
143
+ // Прогресс анимации (от 0 до 1)
144
+ const progress = Math.min(elapsedTime / duration, 1)
145
+
146
+ // Вычисляем новые координаты с помощью линейной интерполяции
147
+ x.value = startX + (newX - startX) * progress
148
+ y.value = startY + (newY - startY) * progress
149
+
150
+ // Если анимация не завершена, продолжаем
151
+ if (progress < 1) {
152
+ requestAnimationFrame(animate)
153
+ }
154
+ }
155
+
156
+ // Запускаем анимацию
157
+ requestAnimationFrame(animate)
158
+ }
159
+
160
+ // Функция для ресайза
161
+ const startResize = (e: any, direction: any): void => {
162
+ e.preventDefault()
163
+
164
+ const startX = e.clientX
165
+ const startY = e.clientY
166
+ const startWidth = width.value
167
+ const startHeight = height.value
168
+ const startLeft = x.value
169
+ const startTop = y.value
170
+
171
+ const onMouseMove = (e: any): void => {
172
+ const deltaX = e.clientX - startX
173
+ const deltaY = e.clientY - startY
174
+
175
+ if (direction.includes('right')) {
176
+ width.value = Math.max(200, startWidth + deltaX)
177
+ }
178
+ if (direction.includes('bottom')) {
179
+ height.value = Math.max(150, startHeight + deltaY)
180
+ }
181
+ if (direction.includes('left')) {
182
+ const newWidth = Math.max(200, startWidth - deltaX)
183
+ if (newWidth !== width.value) {
184
+ x.value = startLeft + deltaX
185
+ width.value = newWidth
186
+ }
187
+ }
188
+ if (direction.includes('top')) {
189
+ const newHeight = Math.max(150, startHeight - deltaY)
190
+ if (newHeight !== height.value) {
191
+ y.value = startTop + deltaY
192
+ height.value = newHeight
193
+ }
194
+ }
195
+ fixSize()
196
+ }
197
+
198
+ const onMouseUp = (): void => {
199
+ document.removeEventListener('mousemove', onMouseMove)
200
+ document.removeEventListener('mouseup', onMouseUp)
201
+ isShowContentBlocker.value = false
202
+ fixPosition()
203
+ }
204
+
205
+ document.addEventListener('mousemove', onMouseMove)
206
+ document.addEventListener('mouseup', onMouseUp)
207
+ isShowContentBlocker.value = true
208
+ }
209
+
210
+ let resizeTimer: any = null
211
+ const globalWindowResize = (): void => {
212
+ clearTimeout(resizeTimer)
213
+
214
+ resizeTimer = setTimeout(() => {
215
+ fixSize()
216
+ fixPosition()
217
+ }, 250)
218
+ }
219
+ onMounted(() => {
220
+ window.addEventListener('resize', globalWindowResize)
221
+ })
222
+ onUnmounted(() => {
223
+ window.removeEventListener('resize', globalWindowResize)
224
+ })
225
+
226
+ const onHide = (): void => {
227
+ emits('hide')
228
+ }
229
+ </script>
230
+
231
+ <style lang="scss">
232
+ .window-container {
233
+ position: absolute;
234
+ border-radius: 8px;
235
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
236
+ overflow: hidden;
237
+ background-color: #fff;
238
+ display: flex;
239
+ flex-direction: column;
240
+ min-width: 300px;
241
+ min-height: 200px;
242
+ z-index: var(--z-toast);
243
+
244
+ .window-header {
245
+ background-color: #314351;
246
+ color: white;
247
+ padding: 6px 12px;
248
+ cursor: move;
249
+ user-select: none;
250
+ display: flex;
251
+ justify-content: space-between;
252
+ align-items: center;
253
+
254
+ .window-title {
255
+ font-weight: 500;
256
+ font-size: 16px;
257
+ }
258
+
259
+ .window-close {
260
+ background: none;
261
+ border: none;
262
+ color: #e4e4e4;
263
+ cursor: pointer;
264
+ width: 20px;
265
+ height: 20px;
266
+ display: flex;
267
+ justify-content: center;
268
+ align-items: center;
269
+
270
+ &:hover {
271
+ color: #ffffff;
272
+ }
273
+ }
274
+ }
275
+
276
+ .window-content {
277
+ position: relative;
278
+ flex-grow: 1;
279
+
280
+ .content-blocker {
281
+ position: absolute;
282
+ top: 0;
283
+ left: 0;
284
+ width: 100%;
285
+ height: 100%;
286
+ z-index: 1;
287
+ }
288
+ }
289
+
290
+ .resize-handle {
291
+ position: absolute;
292
+ background: transparent;
293
+ z-index: 10;
294
+
295
+ &.resize-top {
296
+ top: -3px;
297
+ left: 0;
298
+ right: 0;
299
+ height: 6px;
300
+ cursor: n-resize;
301
+ }
302
+
303
+ &.resize-right {
304
+ top: 0;
305
+ right: -3px;
306
+ bottom: 0;
307
+ width: 6px;
308
+ cursor: e-resize;
309
+ }
310
+
311
+ &.resize-bottom {
312
+ bottom: -3px;
313
+ left: 0;
314
+ right: 0;
315
+ height: 6px;
316
+ cursor: s-resize;
317
+ }
318
+
319
+ &.resize-left {
320
+ top: 0;
321
+ left: -3px;
322
+ bottom: 0;
323
+ width: 6px;
324
+ cursor: w-resize;
325
+ }
326
+
327
+ &.resize-top-left {
328
+ top: -6px;
329
+ left: -6px;
330
+ width: 12px;
331
+ height: 12px;
332
+ cursor: nw-resize;
333
+ }
334
+
335
+ &.resize-top-right {
336
+ top: -6px;
337
+ right: -6px;
338
+ width: 12px;
339
+ height: 12px;
340
+ cursor: ne-resize;
341
+ }
342
+
343
+ &.resize-bottom-left {
344
+ bottom: -6px;
345
+ left: -6px;
346
+ width: 12px;
347
+ height: 12px;
348
+ cursor: sw-resize;
349
+ }
350
+
351
+ &.resize-bottom-right {
352
+ bottom: -6px;
353
+ right: -6px;
354
+ width: 12px;
355
+ height: 12px;
356
+ cursor: se-resize;
357
+ }
358
+ }
359
+ }
360
+ </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bfg-common",
3
3
  "private": false,
4
- "version": "1.5.451",
4
+ "version": "1.5.452",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",