evui 3.3.36 → 3.3.39

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 (141) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +40 -40
  3. package/dist/evui.common.js +1907 -1832
  4. package/dist/evui.common.js.map +1 -1
  5. package/dist/evui.umd.js +1907 -1832
  6. package/dist/evui.umd.js.map +1 -1
  7. package/dist/evui.umd.min.js +1 -1
  8. package/dist/evui.umd.min.js.map +1 -1
  9. package/dist/img/{EVUI.7f3588fb.svg → EVUI.b82ee81a.svg} +292 -292
  10. package/dist/img/{icon_mysql.7ea26d5d.svg → icon_mysql.1085fdc9.svg} +78 -78
  11. package/dist/img/{icon_oracle.9009b108.svg → icon_oracle.0572d3ee.svg} +13 -13
  12. package/dist/img/{icon_postgresql.f8fffba9.svg → icon_postgresql.ee12bde8.svg} +58 -58
  13. package/package.json +61 -61
  14. package/src/common/emitter.js +20 -20
  15. package/src/common/utils.debounce.js +223 -223
  16. package/src/common/utils.js +134 -134
  17. package/src/common/utils.table.js +78 -78
  18. package/src/common/utils.throttle.js +83 -83
  19. package/src/common/utils.tree.js +18 -18
  20. package/src/components/button/Button.vue +198 -198
  21. package/src/components/button/index.js +7 -7
  22. package/src/components/buttonGroup/ButtonGroup.vue +11 -11
  23. package/src/components/buttonGroup/index.js +7 -7
  24. package/src/components/calendar/Calendar.vue +661 -661
  25. package/src/components/calendar/index.js +7 -7
  26. package/src/components/calendar/uses.js +1272 -1272
  27. package/src/components/chart/Chart.vue +189 -192
  28. package/src/components/chart/chart.core.js +870 -870
  29. package/src/components/chart/element/element.bar.js +524 -524
  30. package/src/components/chart/element/element.bar.time.js +156 -156
  31. package/src/components/chart/element/element.heatmap.js +533 -533
  32. package/src/components/chart/element/element.line.js +339 -339
  33. package/src/components/chart/element/element.pie.js +197 -197
  34. package/src/components/chart/element/element.scatter.js +184 -184
  35. package/src/components/chart/element/element.tip.js +550 -542
  36. package/src/components/chart/helpers/helpers.canvas.js +265 -265
  37. package/src/components/chart/helpers/helpers.constant.js +206 -206
  38. package/src/components/chart/helpers/helpers.util.js +346 -338
  39. package/src/components/chart/index.js +9 -9
  40. package/src/components/chart/model/index.js +4 -4
  41. package/src/components/chart/model/model.series.js +93 -93
  42. package/src/components/chart/model/model.store.js +977 -967
  43. package/src/components/chart/plugins/plugins.interaction.js +769 -769
  44. package/src/components/chart/plugins/plugins.legend.gradient.js +602 -602
  45. package/src/components/chart/plugins/plugins.legend.js +1155 -1151
  46. package/src/components/chart/plugins/plugins.pie.js +254 -254
  47. package/src/components/chart/plugins/plugins.title.js +56 -56
  48. package/src/components/chart/plugins/plugins.tooltip.js +692 -692
  49. package/src/components/chart/scale/scale.js +848 -848
  50. package/src/components/chart/scale/scale.linear.js +38 -38
  51. package/src/components/chart/scale/scale.logarithmic.js +128 -128
  52. package/src/components/chart/scale/scale.step.js +336 -336
  53. package/src/components/chart/scale/scale.time.category.js +277 -277
  54. package/src/components/chart/scale/scale.time.js +48 -48
  55. package/src/components/chart/style/chart.scss +312 -312
  56. package/src/components/chart/uses.js +264 -252
  57. package/src/components/checkbox/Checkbox.vue +200 -200
  58. package/src/components/checkbox/index.js +7 -7
  59. package/src/components/checkboxGroup/CheckboxGroup.vue +44 -44
  60. package/src/components/checkboxGroup/index.js +7 -7
  61. package/src/components/contextMenu/ContextMenu.vue +80 -80
  62. package/src/components/contextMenu/MenuList.vue +149 -149
  63. package/src/components/contextMenu/index.js +7 -7
  64. package/src/components/contextMenu/uses.js +203 -203
  65. package/src/components/datePicker/DatePicker.vue +437 -437
  66. package/src/components/datePicker/index.js +7 -7
  67. package/src/components/datePicker/uses.js +419 -419
  68. package/src/components/grid/Grid.vue +827 -827
  69. package/src/components/grid/grid.filter.window.vue +493 -493
  70. package/src/components/grid/grid.pagination.vue +75 -75
  71. package/src/components/grid/grid.summary.vue +265 -265
  72. package/src/components/grid/grid.toolbar.vue +26 -26
  73. package/src/components/grid/index.js +11 -11
  74. package/src/components/grid/style/grid.scss +263 -263
  75. package/src/components/grid/uses.js +1002 -1007
  76. package/src/components/icon/Icon.vue +49 -49
  77. package/src/components/icon/index.js +8 -8
  78. package/src/components/inputNumber/InputNumber.vue +212 -212
  79. package/src/components/inputNumber/index.js +7 -7
  80. package/src/components/inputNumber/uses.js +217 -217
  81. package/src/components/loading/Loading.vue +125 -125
  82. package/src/components/loading/index.js +7 -7
  83. package/src/components/menu/Menu.vue +68 -68
  84. package/src/components/menu/MenuItem.vue +187 -187
  85. package/src/components/menu/index.js +7 -7
  86. package/src/components/message/Message.vue +223 -223
  87. package/src/components/message/index.js +31 -31
  88. package/src/components/messageBox/MessageBox.vue +358 -358
  89. package/src/components/messageBox/index.js +22 -22
  90. package/src/components/notification/Notification.vue +316 -316
  91. package/src/components/notification/index.js +49 -49
  92. package/src/components/pagination/Pagination.vue +271 -271
  93. package/src/components/pagination/index.js +7 -7
  94. package/src/components/pagination/pageButton.vue +30 -30
  95. package/src/components/progress/Progress.vue +139 -139
  96. package/src/components/progress/index.js +7 -7
  97. package/src/components/radio/Radio.vue +159 -159
  98. package/src/components/radio/index.js +7 -7
  99. package/src/components/radioGroup/RadioGroup.vue +41 -41
  100. package/src/components/radioGroup/index.js +7 -7
  101. package/src/components/scheduler/Scheduler.vue +149 -149
  102. package/src/components/scheduler/index.js +7 -7
  103. package/src/components/scheduler/uses.js +183 -183
  104. package/src/components/select/Select.vue +440 -440
  105. package/src/components/select/index.js +7 -7
  106. package/src/components/select/uses.js +270 -270
  107. package/src/components/slider/Slider.vue +505 -505
  108. package/src/components/slider/index.js +7 -7
  109. package/src/components/slider/uses.js +390 -390
  110. package/src/components/tabPanel/TabPanel.vue +74 -74
  111. package/src/components/tabPanel/index.js +7 -7
  112. package/src/components/tabs/Tabs.vue +517 -517
  113. package/src/components/tabs/index.js +7 -7
  114. package/src/components/textField/TextField.vue +375 -375
  115. package/src/components/textField/index.js +7 -7
  116. package/src/components/timePicker/TimePicker.vue +352 -352
  117. package/src/components/timePicker/index.js +7 -7
  118. package/src/components/toggle/Toggle.vue +115 -115
  119. package/src/components/toggle/index.js +7 -7
  120. package/src/components/tree/Tree.vue +313 -313
  121. package/src/components/tree/TreeNode.vue +293 -293
  122. package/src/components/tree/index.js +7 -7
  123. package/src/components/treeGrid/TreeGrid.vue +758 -758
  124. package/src/components/treeGrid/TreeGridNode.vue +275 -275
  125. package/src/components/treeGrid/index.js +9 -9
  126. package/src/components/treeGrid/style/treeGrid.scss +261 -261
  127. package/src/components/treeGrid/treeGrid.toolbar.vue +26 -26
  128. package/src/components/treeGrid/uses.js +867 -867
  129. package/src/components/window/Window.vue +329 -329
  130. package/src/components/window/index.js +7 -7
  131. package/src/components/window/uses.js +899 -899
  132. package/src/directives/clickoutside.js +90 -90
  133. package/src/main.js +116 -116
  134. package/src/style/components/input.scss +108 -108
  135. package/src/style/functions.scss +3 -3
  136. package/src/style/index.scss +6 -6
  137. package/src/style/lib/fonts/EVUI.svg +292 -292
  138. package/src/style/lib/icon.css +888 -888
  139. package/src/style/mixins.scss +94 -94
  140. package/src/style/themes.scss +67 -67
  141. package/src/style/variables.scss +22 -22
@@ -1,899 +1,899 @@
1
- import {
2
- getCurrentInstance,
3
- ref,
4
- computed,
5
- reactive,
6
- watch,
7
- nextTick,
8
- onMounted,
9
- onBeforeUnmount,
10
- } from 'vue';
11
-
12
- // 세로 스크롤 너비
13
- const getVScrollWidth = () => window.innerWidth - document.documentElement.clientWidth;
14
- // 가로 스크롤 너비
15
- // const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
16
-
17
- const useModel = () => {
18
- const { props, emit } = getCurrentInstance();
19
-
20
- const windowRef = ref();
21
- const headerRef = ref();
22
- const isFullExpandWindow = ref(false);
23
- const maximizableIcon = computed(() => (isFullExpandWindow.value ? 'ev-icon-compress' : 'ev-icon-expand'));
24
-
25
- // body에 #ev-window-modal div append
26
- let root = document.getElementById('ev-window-modal');
27
- const initWrapperDiv = () => {
28
- if (!root) {
29
- const rootDiv = document.createElement('div');
30
- rootDiv.id = 'ev-window-modal';
31
- document.body.appendChild(rootDiv);
32
- root = document.getElementById('ev-window-modal');
33
- }
34
- };
35
- initWrapperDiv();
36
-
37
- const numberToUnit = (input) => {
38
- let output;
39
- let result;
40
-
41
- if (typeof input === 'string' || typeof input === 'number') {
42
- const match = (/^(normal|(-*\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
43
- output = match ? { value: +match[2], unit: match[3] || undefined } : undefined;
44
- } else {
45
- output = undefined;
46
- }
47
-
48
- if (output === null || output === undefined) {
49
- result = undefined;
50
- } else if (output.unit) {
51
- result = `${output.value}${output.unit}`;
52
- } else {
53
- result = `${output.value}px`;
54
- }
55
-
56
- return result;
57
- };
58
-
59
- const removeUnit = (input, direction = 'horizontal') => {
60
- if (typeof input === 'number') {
61
- return input;
62
- } else if (!input) {
63
- return 0;
64
- }
65
-
66
- let result = 0;
67
- const match = (/^(normal|(\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
68
-
69
- if (direction && ['%', 'vw', 'vh'].includes(match[3]) && match[2]) {
70
- const standard = direction === 'horizontal' ? window.innerWidth : window.innerHeight;
71
- result = Math.floor((standard * +match[2]) / 100);
72
- } else if (match[2]) {
73
- result = +match[2];
74
- }
75
-
76
- return result;
77
- };
78
-
79
- // set base style
80
- const basePosition = reactive({});
81
- const baseStyle = computed(() => ({
82
- ...props.style,
83
- ...basePosition,
84
- }));
85
-
86
- const setBasePosition = () => {
87
- basePosition.position = 'fixed';
88
-
89
- if (props.fullscreen) {
90
- basePosition.width = '100%';
91
- basePosition.height = '100%';
92
- basePosition.top = 0;
93
- basePosition.left = 0;
94
- return;
95
- }
96
-
97
- const convertedWidth = removeUnit(props.width, 'horizontal');
98
- const convertedMinWidth = removeUnit(props.minWidth, 'horizontal');
99
- if (convertedWidth < convertedMinWidth) {
100
- console.warn('Since width is less than min-width, it is replaced by min-width.');
101
- basePosition.width = numberToUnit(props.minWidth);
102
- } else {
103
- basePosition.width = numberToUnit(props.width);
104
- }
105
-
106
- const convertedHeight = removeUnit(props.height, 'vertical');
107
- const convertedMinHeight = removeUnit(props.minHeight, 'vertical');
108
- if (convertedHeight < convertedMinHeight) {
109
- console.warn('Since height is less than min-height, it is replaced by min-height.');
110
- basePosition.height = numberToUnit(props.minHeight);
111
- } else {
112
- basePosition.height = numberToUnit(props.height);
113
- }
114
-
115
- basePosition.top = `calc((100% - ${basePosition.height}) / 2)`;
116
- basePosition.left = `calc((100% - ${basePosition.width}) / 2)`;
117
-
118
- if (removeUnit(props.width, 'horizontal') > window.innerWidth) {
119
- basePosition.left = 0;
120
- }
121
- if (removeUnit(props.height, 'vertical') > window.innerHeight) {
122
- basePosition.top = 0;
123
- }
124
- };
125
-
126
- // close window
127
- const closeWin = (from) => {
128
- if (from === 'layer' && !props.closeOnClickModal) {
129
- return;
130
- }
131
- emit('update:visible', false);
132
- };
133
-
134
- const changeBodyCls = (isVisible) => {
135
- const hideScrollWindowCnt = root?.getElementsByClassName('scroll-lock')?.length;
136
- const bodyElem = document.body;
137
-
138
- if (isVisible) { // window open
139
- if (props.hideScroll) {
140
- // hideScroll 시, body 우측 padding 추가 & overflow hidden class 추가
141
- if (!hideScrollWindowCnt) {
142
- const scrollWidth = getVScrollWidth();
143
- bodyElem.style.paddingRight = `${scrollWidth}px`;
144
- }
145
- bodyElem.classList.add('ev-window-scroll-lock');
146
- }
147
- } else if (props.hideScroll && hideScrollWindowCnt === 1) { // window close
148
- bodyElem.style.removeProperty('padding-right');
149
- bodyElem.classList.remove('ev-window-scroll-lock');
150
- }
151
- };
152
-
153
- setBasePosition();
154
-
155
- watch(
156
- () => props.visible,
157
- async (newVal) => {
158
- changeBodyCls(newVal);
159
- if (newVal) {
160
- await nextTick(() => {
161
- setBasePosition();
162
- });
163
- }
164
- },
165
- );
166
-
167
- return {
168
- windowRef,
169
- headerRef,
170
- isFullExpandWindow,
171
- maximizableIcon,
172
- baseStyle,
173
- closeWin,
174
- numberToUnit,
175
- removeUnit,
176
- };
177
- };
178
-
179
- const useMouseEvent = (param) => {
180
- const { props, emit } = getCurrentInstance();
181
- const {
182
- windowRef,
183
- headerRef,
184
- isFullExpandWindow,
185
- numberToUnit,
186
- removeUnit,
187
- } = param;
188
-
189
- const draggingMinSize = 50;
190
- const grabbingBorderSize = 5;
191
- const dragStyle = reactive({});
192
- const clickedInfo = reactive({
193
- state: '',
194
- pressedSpot: '',
195
- top: 0,
196
- left: 0,
197
- width: 0,
198
- height: 0,
199
- clientX: 0,
200
- clientY: 0,
201
- });
202
- const draggedInfo = reactive({
203
- top: 0,
204
- left: 0,
205
- });
206
- const grabbingBorderPosInfo = reactive({
207
- top: false,
208
- right: false,
209
- left: false,
210
- bottom: false,
211
- });
212
- const beforeExpandPosInfo = reactive({
213
- width: null,
214
- height: null,
215
- top: null,
216
- left: null,
217
- });
218
-
219
- const isInHeader = (x, y) => {
220
- if (x == null || y == null) {
221
- return false;
222
- }
223
-
224
- const rect = windowRef.value.getBoundingClientRect();
225
- const posX = +x - rect.left;
226
- const posY = +y - rect.top;
227
- const headerAreaStyleInfo = headerRef.value.style;
228
- const headerPaddingInfo = {
229
- top: removeUnit(headerAreaStyleInfo.paddingTop, 'vertical'),
230
- left: removeUnit(headerAreaStyleInfo.paddingLeft, 'horizontal'),
231
- right: removeUnit(headerAreaStyleInfo.paddingRight, 'horizontal'),
232
- };
233
- const startPosX = headerPaddingInfo.left;
234
- const endPosX = rect.width - headerPaddingInfo.right;
235
- const startPosY = headerPaddingInfo.top;
236
- const endPosY = startPosY + headerRef.value.offsetHeight;
237
-
238
- return posX > startPosX && posX < endPosX && posY > startPosY && posY < endPosY;
239
- };
240
-
241
- const setDragStyle = (paramObj) => {
242
- if (paramObj === null || typeof paramObj !== 'object') {
243
- return;
244
- }
245
-
246
- let top;
247
- let left;
248
- let width;
249
- let height;
250
- let tMinWidth;
251
- let tMinHeight;
252
- const windowEl = windowRef.value;
253
- const hasOwnProperty = Object.prototype.hasOwnProperty;
254
-
255
- if (hasOwnProperty.call(paramObj, 'top')) {
256
- top = paramObj.top;
257
- } else {
258
- top = clickedInfo.top;
259
- }
260
-
261
- if (hasOwnProperty.call(paramObj, 'left')) {
262
- left = paramObj.left;
263
- } else {
264
- left = clickedInfo.left;
265
- }
266
-
267
- if (hasOwnProperty.call(paramObj, 'width')) {
268
- width = paramObj.width;
269
- } else {
270
- width = windowEl.offsetWidth;
271
- }
272
-
273
- if (hasOwnProperty.call(paramObj, 'height')) {
274
- height = paramObj.height;
275
- } else {
276
- height = windowEl.offsetHeight;
277
- }
278
-
279
- if (hasOwnProperty.call(paramObj, 'minWidth')) {
280
- tMinWidth = paramObj.minWidth;
281
- } else {
282
- tMinWidth = props.minWidth;
283
- }
284
-
285
- if (hasOwnProperty.call(paramObj, 'minHeight')) {
286
- tMinHeight = paramObj.minHeight;
287
- } else {
288
- tMinHeight = props.minHeight;
289
- }
290
-
291
- width = removeUnit(width, 'horizontal') > removeUnit(tMinWidth, 'horizontal') ? width : tMinWidth;
292
- height = removeUnit(height, 'vertical') > removeUnit(tMinHeight, 'vertical') ? height : tMinHeight;
293
-
294
- dragStyle.top = numberToUnit(top);
295
- dragStyle.left = numberToUnit(left);
296
- dragStyle.width = numberToUnit(width);
297
- dragStyle.height = numberToUnit(height);
298
- dragStyle.minWidth = numberToUnit(tMinWidth);
299
- dragStyle.minHeight = numberToUnit(tMinHeight);
300
- };
301
-
302
- const changeMouseCursor = (e) => {
303
- if (!windowRef.value || clickedInfo.pressedSpot) {
304
- return;
305
- }
306
-
307
- if (props.resizable) {
308
- const rect = windowRef.value.getBoundingClientRect();
309
- const x = e.clientX - rect.left;
310
- const y = e.clientY - rect.top;
311
- const top = y < grabbingBorderSize;
312
- const left = x < grabbingBorderSize;
313
- const right = x >= (rect.width - grabbingBorderSize);
314
- const bottom = y >= (rect.height - grabbingBorderSize);
315
-
316
- if ((top && left) || (bottom && right)) {
317
- windowRef.value.style.cursor = 'nwse-resize';
318
- } else if ((top && right) || (bottom && left)) {
319
- windowRef.value.style.cursor = 'nesw-resize';
320
- } else if (right || left) {
321
- windowRef.value.style.cursor = 'ew-resize';
322
- } else if (bottom || top) {
323
- windowRef.value.style.cursor = 'ns-resize';
324
- } else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
325
- windowRef.value.style.cursor = 'move';
326
- } else {
327
- windowRef.value.style.cursor = 'default';
328
- }
329
- } else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
330
- windowRef.value.style.cursor = 'move';
331
- } else {
332
- windowRef.value.style.cursor = 'default';
333
- }
334
- };
335
-
336
- // window resize
337
- const resizeWindow = (e) => {
338
- const windowWidth = window.innerWidth;
339
- const windowHeight = window.innerHeight;
340
- const isTop = grabbingBorderPosInfo.top;
341
- const isLeft = grabbingBorderPosInfo.left;
342
- const isRight = grabbingBorderPosInfo.right;
343
- const isBottom = grabbingBorderPosInfo.bottom;
344
- const minWidth = removeUnit(props.minWidth, 'horizontal');
345
- const minHeight = removeUnit(props.minHeight, 'vertical');
346
- const clientX = e.clientX >= windowWidth ? windowWidth : e.clientX;
347
- let clientY = e.clientY >= windowHeight ? windowHeight : e.clientY;
348
- clientY = e.clientY > 0 ? clientY : 0;
349
- const diffX = clientX - clickedInfo.clientX;
350
- const diffY = clientY - clickedInfo.clientY;
351
-
352
- let top = clickedInfo.top;
353
- let left = clickedInfo.left;
354
- let width = clickedInfo.width;
355
- let height = clickedInfo.height;
356
- const maxTop = (top + clickedInfo.height) - minHeight;
357
- const maxLeft = (left + clickedInfo.width) - minWidth;
358
-
359
- if (isTop) {
360
- top = clickedInfo.top + diffY;
361
- height = clickedInfo.height - diffY;
362
-
363
- if (top > maxTop) {
364
- top = maxTop;
365
- }
366
- }
367
-
368
- if (isLeft) {
369
- left = clickedInfo.left + diffX;
370
- width = clickedInfo.width - diffX;
371
-
372
- if (left > maxLeft) {
373
- left = maxLeft;
374
- }
375
- }
376
-
377
- if (isRight) {
378
- width = clickedInfo.width + diffX;
379
- }
380
-
381
- if (isBottom) {
382
- height = clickedInfo.height + diffY;
383
- }
384
-
385
- width = Math.min(Math.max(width, minWidth), windowWidth);
386
- height = Math.min(Math.max(height, minHeight), windowHeight);
387
-
388
- const positionInfo = { top, left, width, height };
389
- setDragStyle(positionInfo);
390
- emit('resize', e, { ...positionInfo });
391
- };
392
-
393
- // 브라우저 상하 위치 제약
394
- const getValidTop = (windowHeight, top) => {
395
- let tempTop = top;
396
-
397
- if (tempTop < 0) { // 상
398
- tempTop = 0;
399
- } else if (tempTop > windowHeight - draggingMinSize) { // 하
400
- tempTop = Math.floor(windowHeight - draggingMinSize);
401
- }
402
- return tempTop;
403
- };
404
- // 브라우저 좌우 위치 제약
405
- const getValidLeft = (windowWidth, left) => {
406
- let tempLeft = left;
407
- if (tempLeft < -(clickedInfo.width - draggingMinSize)) { // 좌
408
- tempLeft = -Math.floor(clickedInfo.width - draggingMinSize);
409
- } else if (tempLeft > windowWidth - draggingMinSize) { // 우
410
- tempLeft = Math.floor(windowWidth - draggingMinSize);
411
- }
412
- return tempLeft;
413
- };
414
-
415
- // mousedown > mousemove: 마우스 드래그
416
- const dragging = (e) => {
417
- e.preventDefault();
418
- clickedInfo.state = 'mousedown-mousemove';
419
-
420
- // window header를 통해 mouseMove 됐을 경우
421
- if (props.draggable && clickedInfo.pressedSpot === 'header') {
422
- const windowWidth = document.documentElement.clientWidth;
423
- const windowHeight = document.documentElement.clientHeight;
424
- const diffTop = e.clientY - clickedInfo.clientY;
425
- const diffLeft = e.clientX - clickedInfo.clientX;
426
-
427
- let tempTop = clickedInfo.top + diffTop;
428
- let tempLeft = clickedInfo.left + diffLeft;
429
-
430
- tempTop = getValidTop(windowHeight, tempTop);
431
- tempLeft = getValidLeft(windowWidth, tempLeft);
432
-
433
- setDragStyle({
434
- top: `${tempTop}px`,
435
- left: `${tempLeft}px`,
436
- width: dragStyle.width ?? props.width,
437
- height: dragStyle.height ?? props.height,
438
- });
439
- } else if (props.resizable && clickedInfo.pressedSpot === 'border') {
440
- resizeWindow(e);
441
- }
442
-
443
- emit('mousedown-mousemove', e);
444
- };
445
-
446
- // mousedown > mouseup: 마우스 드래그 종료
447
- const endDrag = (e) => {
448
- clickedInfo.state = '';
449
- clickedInfo.pressedSpot = '';
450
-
451
- emit('mousedown-mouseup', e);
452
-
453
- window.removeEventListener('mousemove', dragging);
454
- window.removeEventListener('mouseup', endDrag);
455
- };
456
-
457
- // mousedown: 드래그 시작
458
- const startDrag = (e) => {
459
- if (!windowRef.value || (!props.resizable && !props.draggable)) {
460
- return;
461
- }
462
- let pressedSpot = '';
463
- if (props.resizable) {
464
- const clientRect = windowRef.value.getBoundingClientRect();
465
- const x = e.clientX - clientRect.left;
466
- const y = e.clientY - clientRect.top;
467
- const isGrabTop = y < grabbingBorderSize;
468
- const isGrabLeft = x < grabbingBorderSize;
469
- const isGrabRight = x >= (clientRect.width - grabbingBorderSize);
470
- const isGrabBottom = y >= (clientRect.height - grabbingBorderSize);
471
-
472
- grabbingBorderPosInfo.top = isGrabTop;
473
- grabbingBorderPosInfo.left = isGrabLeft;
474
- grabbingBorderPosInfo.right = isGrabRight;
475
- grabbingBorderPosInfo.bottom = isGrabBottom;
476
-
477
- if (isGrabTop || isGrabLeft || isGrabRight || isGrabBottom) {
478
- pressedSpot = 'border';
479
- }
480
- }
481
-
482
- if (pressedSpot !== 'border' && isInHeader(e.clientX, e.clientY)) {
483
- pressedSpot = 'header';
484
- }
485
-
486
- if (!pressedSpot
487
- || (!props.draggable && pressedSpot === 'header')
488
- || (!props.resizable && pressedSpot === 'border')
489
- ) {
490
- return;
491
- }
492
-
493
- clickedInfo.state = 'mousedown';
494
- clickedInfo.pressedSpot = pressedSpot;
495
- clickedInfo.top = windowRef.value.offsetTop;
496
- clickedInfo.left = windowRef.value.offsetLeft;
497
- clickedInfo.width = windowRef.value.offsetWidth;
498
- clickedInfo.height = windowRef.value.offsetHeight;
499
- clickedInfo.clientX = e.clientX;
500
- clickedInfo.clientY = e.clientY;
501
-
502
- emit('mousedown', { ...clickedInfo });
503
-
504
- window.addEventListener('mousemove', dragging);
505
- window.addEventListener('mouseup', endDrag);
506
- };
507
-
508
- const moveMouse = (e) => {
509
- if (!props.draggable && !props.resizable) {
510
- return;
511
- }
512
- changeMouseCursor(e);
513
- };
514
-
515
- const clickExpandBtn = () => {
516
- isFullExpandWindow.value = !isFullExpandWindow.value;
517
- nextTick(() => {
518
- if (isFullExpandWindow.value) {
519
- beforeExpandPosInfo.top = windowRef.value.offsetTop;
520
- beforeExpandPosInfo.left = windowRef.value.offsetLeft;
521
- beforeExpandPosInfo.width = windowRef.value.offsetWidth;
522
- beforeExpandPosInfo.height = windowRef.value.offsetHeight;
523
-
524
- setDragStyle({
525
- top: 0,
526
- left: 0,
527
- width: document.body.clientWidth,
528
- height: document.body.clientHeight,
529
- });
530
- } else {
531
- setDragStyle({
532
- top: beforeExpandPosInfo.top,
533
- left: beforeExpandPosInfo.left,
534
- width: beforeExpandPosInfo.width,
535
- height: beforeExpandPosInfo.height,
536
- });
537
- }
538
-
539
- emit('expand', {
540
- top: beforeExpandPosInfo.top,
541
- left: beforeExpandPosInfo.left,
542
- width: beforeExpandPosInfo.width,
543
- height: beforeExpandPosInfo.height,
544
- });
545
- });
546
- };
547
-
548
- const initWindowInfo = () => {
549
- isFullExpandWindow.value = false;
550
-
551
- clickedInfo.state = '';
552
- clickedInfo.pressedSpot = '';
553
- clickedInfo.top = 0;
554
- clickedInfo.left = 0;
555
- clickedInfo.width = 0;
556
- clickedInfo.height = 0;
557
- clickedInfo.clientX = 0;
558
- clickedInfo.clientY = 0;
559
-
560
- draggedInfo.top = 0;
561
- draggedInfo.left = 0;
562
-
563
- grabbingBorderPosInfo.top = false;
564
- grabbingBorderPosInfo.left = false;
565
- grabbingBorderPosInfo.right = false;
566
- grabbingBorderPosInfo.bottom = false;
567
-
568
- beforeExpandPosInfo.top = null;
569
- beforeExpandPosInfo.left = null;
570
- beforeExpandPosInfo.width = null;
571
- beforeExpandPosInfo.height = null;
572
-
573
- Object.keys(dragStyle).forEach((key) => {
574
- delete dragStyle[key];
575
- });
576
- };
577
-
578
- watch(
579
- () => props.visible,
580
- (newVal) => {
581
- if (!newVal) {
582
- initWindowInfo();
583
- }
584
- },
585
- );
586
-
587
- return {
588
- dragStyle,
589
- startDrag,
590
- moveMouse,
591
- clickExpandBtn,
592
- };
593
- };
594
-
595
- const activeWindows = (() => {
596
- let windows = [];
597
- let sequence = 0;
598
-
599
- return {
600
- add(activeWindow) {
601
- if (activeWindow === null || activeWindow === undefined) return;
602
-
603
- activeWindow.sequence = sequence++;
604
- windows.push(activeWindow);
605
-
606
- // eslint-disable-next-line consistent-return
607
- return activeWindow.sequence;
608
- },
609
- remove(inactiveWindow) {
610
- if (inactiveWindow === null || inactiveWindow === undefined) return;
611
- windows = windows.filter(activeWindow => activeWindow.sequence !== inactiveWindow.sequence);
612
- },
613
-
614
- get windows() {
615
- return windows.slice();
616
- },
617
- getWindowBySequence(targetSequence) {
618
- return windows.find(activeWindow => activeWindow.sequence === targetSequence);
619
- },
620
-
621
- isEmpty() {
622
- return windows.length <= 0;
623
- },
624
- isFirstWindowOpen() {
625
- return sequence === 1;
626
- },
627
- };
628
- })();
629
-
630
- const zIndexService = (() => {
631
- const LOWER = 700;
632
- const UPPER = 750;
633
-
634
- const INCREMENT = 1;
635
- const PADDING = INCREMENT * 2;
636
-
637
- const UPPER_LIMIT = UPPER - PADDING;
638
-
639
- let current = LOWER;
640
-
641
- return {
642
- getNext() {
643
- if (current >= UPPER_LIMIT) {
644
- return UPPER_LIMIT;
645
- }
646
- current += INCREMENT;
647
- return current;
648
- },
649
- getNextOverLimit() {
650
- return UPPER_LIMIT + INCREMENT;
651
- },
652
- getPrevFrom(index) {
653
- const prev = current - (index * INCREMENT);
654
-
655
- if (prev <= LOWER) return LOWER;
656
- return prev;
657
- },
658
- isUpperLimitClose() {
659
- return current >= UPPER_LIMIT;
660
- },
661
- resetToLower() {
662
- current = LOWER;
663
- },
664
- getAllocableCount() {
665
- return Math.floor((UPPER_LIMIT - LOWER) / INCREMENT);
666
- },
667
- };
668
- })();
669
-
670
- const getZIndexFromElement = (element) => {
671
- const zIndex = window.getComputedStyle(element).getPropertyValue('z-index').trim();
672
-
673
- if (!zIndex || isNaN(zIndex)) return 700; // window 초기 z-index 값
674
-
675
- return parseInt(zIndex);
676
- };
677
-
678
- const getActiveWindowsOrderByZIndexAsc = () => {
679
- // zIndex 클수록, 최근에 열린 것일수록(sequence 클수록) 뒤에 위치
680
- const compareByZIndex = (window1, window2) => {
681
- if (window1.zIndex > window2.zIndex) return 1;
682
- if (window1.zIndex < window2.zIndex) return -1;
683
-
684
- if (window1.sequence > window2.sequence) return 1;
685
- return -1;
686
- };
687
-
688
- const activeWindowsSorted = Array.prototype.map.call(activeWindows.windows, activeWindow => ({
689
- ...activeWindow,
690
- zIndex: getZIndexFromElement(activeWindow.elem),
691
- })).sort(compareByZIndex);
692
-
693
- return activeWindowsSorted;
694
- };
695
-
696
- const useEscCloseAndFocusable = ({ closeWin, windowRef }) => {
697
- const { props } = getCurrentInstance();
698
-
699
- let sequence = null;
700
- let timer = null;
701
-
702
- // escClose 관련 로직 시작
703
- const addActiveWindow = () => {
704
- const windowSequence = activeWindows.add({
705
- sequence,
706
- closeWin,
707
- elem: windowRef.value,
708
- escClose: props.escClose,
709
- });
710
- return windowSequence;
711
- };
712
-
713
- const removeInactiveWindow = (inactiveWindow) => {
714
- activeWindows.remove(inactiveWindow);
715
- };
716
-
717
- const keydownEsc = (event) => {
718
- if (activeWindows.isEmpty()) return;
719
-
720
- const { code } = event;
721
- if (code !== 'Escape') return;
722
-
723
- const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
724
- const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
725
-
726
- // 예시 상황) Nested에서 외부 Window의 escClose는 true이고, 내부 Window의 escClose는 false인 경우,
727
- // esc 눌러도 외부 Window는 닫히지 않고, 가장 상단에 있는 내부 Window가 수동으로 닫힌 후에 닫히도록 하기 위해
728
- if (!topActiveWindow.escClose) return;
729
-
730
- topActiveWindow.closeWin();
731
- };
732
-
733
- const setWindowActive = () => {
734
- sequence = addActiveWindow();
735
- // DOM의 dataset에 sequence 값 추가해 식별 가능하도록
736
- windowRef.value.dataset.sequence = sequence;
737
-
738
- if (activeWindows.isFirstWindowOpen()) {
739
- document.addEventListener('keydown', keydownEsc);
740
- }
741
- };
742
-
743
- const setWindowInactive = () => {
744
- const inactiveWindow = activeWindows.getWindowBySequence(sequence);
745
- removeInactiveWindow(inactiveWindow);
746
- };
747
- // escClose 관련 로직 끝
748
-
749
-
750
- // focusable 관련 로직 시작
751
- const setZIndexToWindow = ({ elem, zIndex }) => {
752
- // 모달인 경우에는 dim layer도 같이 z-index 높여준다.
753
- if (props.isModal) {
754
- const dimLayerElem = elem.parentElement.getElementsByClassName('ev-window-dim-layer')[0];
755
- dimLayerElem.style.zIndex = zIndex;
756
- }
757
-
758
- elem.style.zIndex = zIndex;
759
- };
760
-
761
- const assignZIndex = () => {
762
- // Window가 1번째로 열릴 때, z-index 값을 시작값으로 설정
763
- if (activeWindows.windows.length === 1) {
764
- zIndexService.resetToLower();
765
- }
766
-
767
- const nextZIndex = zIndexService.getNext();
768
- setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
769
- };
770
-
771
- const sameAsCurrent = windowData => String(windowData.sequence)
772
- === windowRef.value.dataset.sequence;
773
-
774
- // 할당하려는 z-index 값이 상한일 때
775
- const reassignZIndex = () => {
776
- const activeWindowsZIndexAsc = getActiveWindowsOrderByZIndexAsc();
777
-
778
- const overCountLimit = activeWindows.windows.length > zIndexService.getAllocableCount();
779
- // 할당 가능한 z-index 수보다 많은 Window를 띄웠을 때
780
- if (overCountLimit) {
781
- const activeWindowsZIndexDesc = activeWindowsZIndexAsc.reverse();
782
-
783
- // z-index 기준 내림차순으로 정렬한 Window의 z-index 값을 UPPER에서 LOWER로 1씩 감소한 값 할당
784
- let interval = 0;
785
- activeWindowsZIndexDesc.forEach((activeWindow) => {
786
- if (sameAsCurrent(activeWindow)) return;
787
-
788
- const prevZIndex = zIndexService.getPrevFrom(interval++);
789
- setZIndexToWindow({ elem: activeWindow.elem, zIndex: prevZIndex });
790
- });
791
-
792
- // 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
793
- const nextZIndex = zIndexService.getNextOverLimit();
794
- setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
795
- } else {
796
- zIndexService.resetToLower();
797
-
798
- activeWindowsZIndexAsc.forEach((activeWindow) => {
799
- if (sameAsCurrent(activeWindow)) return;
800
-
801
- const nextZIndex = zIndexService.getNext();
802
- setZIndexToWindow({ elem: activeWindow.elem, zIndex: nextZIndex });
803
- });
804
-
805
- // 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
806
- const nextZIndex = zIndexService.getNext();
807
- setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
808
- }
809
- };
810
-
811
- const checkLimitAndSetZIndex = () => {
812
- if (zIndexService.isUpperLimitClose()) {
813
- reassignZIndex();
814
- } else {
815
- assignZIndex();
816
- }
817
- };
818
-
819
- const setFocus = () => {
820
- // X 버튼을 클릭했을 때
821
- if (!windowRef.value) return;
822
-
823
- // focusable prop이 false인 경우에는 z-index를 높이지 않는다.
824
- if (!props.focusable) return;
825
-
826
- const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
827
- const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
828
-
829
- const isAlreadyTop = sameAsCurrent(topActiveWindow);
830
- if (isAlreadyTop) return;
831
-
832
- checkLimitAndSetZIndex();
833
- };
834
- // focusable 관련 로직 끝
835
-
836
-
837
- /*
838
- 실행 시점(=Window 열림):
839
- visible 초기값이 true일 때 watch를 실행시키지 않아 onMounted hook 사용
840
- */
841
- onMounted(() => {
842
- if (props.visible) {
843
- setWindowActive();
844
- timer = setTimeout(checkLimitAndSetZIndex, 0);
845
- }
846
- });
847
-
848
- /*
849
- 실행 시점(=Window 닫힘):
850
- 예시. 배열을 통해 Window 여러 개 띄울 때, 배열 원소 삭제로 인해 해당 Window가 닫히는 경우
851
- unmount가 발생해서 watch를 실행히시키지 않아 onBeforeUnmount hook 사용
852
- */
853
- onBeforeUnmount(() => {
854
- if (props.visible) {
855
- setWindowInactive();
856
- clearTimeout(timer);
857
- }
858
- });
859
-
860
- /*
861
- 실행 시점:
862
- 1. visible 값이 false -> true로 변했을 때(=Window 열림)
863
- 2. visible 값이 true -> false로 변했을 때(=Window 닫힙)
864
- */
865
- watch(
866
- () => props.visible,
867
- (visible) => {
868
- nextTick(() => {
869
- if (visible) {
870
- // visible 값이 false -> true로 변경되었을 때
871
- setWindowActive();
872
- timer = setTimeout(checkLimitAndSetZIndex, 0);
873
- } else {
874
- // visible 값이 true -> false로 변경되었을 때
875
- setWindowInactive();
876
- clearTimeout(timer);
877
- }
878
- });
879
- });
880
-
881
- watch(
882
- () => props.escClose,
883
- (escClose) => {
884
- if (!props.visible) return;
885
- const currentWindow = activeWindows.getWindowBySequence(sequence);
886
- if (currentWindow) currentWindow.escClose = escClose;
887
- },
888
- );
889
-
890
- return {
891
- setFocus,
892
- };
893
- };
894
-
895
- export {
896
- useModel,
897
- useMouseEvent,
898
- useEscCloseAndFocusable,
899
- };
1
+ import {
2
+ getCurrentInstance,
3
+ ref,
4
+ computed,
5
+ reactive,
6
+ watch,
7
+ nextTick,
8
+ onMounted,
9
+ onBeforeUnmount,
10
+ } from 'vue';
11
+
12
+ // 세로 스크롤 너비
13
+ const getVScrollWidth = () => window.innerWidth - document.documentElement.clientWidth;
14
+ // 가로 스크롤 너비
15
+ // const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
16
+
17
+ const useModel = () => {
18
+ const { props, emit } = getCurrentInstance();
19
+
20
+ const windowRef = ref();
21
+ const headerRef = ref();
22
+ const isFullExpandWindow = ref(false);
23
+ const maximizableIcon = computed(() => (isFullExpandWindow.value ? 'ev-icon-compress' : 'ev-icon-expand'));
24
+
25
+ // body에 #ev-window-modal div append
26
+ let root = document.getElementById('ev-window-modal');
27
+ const initWrapperDiv = () => {
28
+ if (!root) {
29
+ const rootDiv = document.createElement('div');
30
+ rootDiv.id = 'ev-window-modal';
31
+ document.body.appendChild(rootDiv);
32
+ root = document.getElementById('ev-window-modal');
33
+ }
34
+ };
35
+ initWrapperDiv();
36
+
37
+ const numberToUnit = (input) => {
38
+ let output;
39
+ let result;
40
+
41
+ if (typeof input === 'string' || typeof input === 'number') {
42
+ const match = (/^(normal|(-*\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
43
+ output = match ? { value: +match[2], unit: match[3] || undefined } : undefined;
44
+ } else {
45
+ output = undefined;
46
+ }
47
+
48
+ if (output === null || output === undefined) {
49
+ result = undefined;
50
+ } else if (output.unit) {
51
+ result = `${output.value}${output.unit}`;
52
+ } else {
53
+ result = `${output.value}px`;
54
+ }
55
+
56
+ return result;
57
+ };
58
+
59
+ const removeUnit = (input, direction = 'horizontal') => {
60
+ if (typeof input === 'number') {
61
+ return input;
62
+ } else if (!input) {
63
+ return 0;
64
+ }
65
+
66
+ let result = 0;
67
+ const match = (/^(normal|(\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
68
+
69
+ if (direction && ['%', 'vw', 'vh'].includes(match[3]) && match[2]) {
70
+ const standard = direction === 'horizontal' ? window.innerWidth : window.innerHeight;
71
+ result = Math.floor((standard * +match[2]) / 100);
72
+ } else if (match[2]) {
73
+ result = +match[2];
74
+ }
75
+
76
+ return result;
77
+ };
78
+
79
+ // set base style
80
+ const basePosition = reactive({});
81
+ const baseStyle = computed(() => ({
82
+ ...props.style,
83
+ ...basePosition,
84
+ }));
85
+
86
+ const setBasePosition = () => {
87
+ basePosition.position = 'fixed';
88
+
89
+ if (props.fullscreen) {
90
+ basePosition.width = '100%';
91
+ basePosition.height = '100%';
92
+ basePosition.top = 0;
93
+ basePosition.left = 0;
94
+ return;
95
+ }
96
+
97
+ const convertedWidth = removeUnit(props.width, 'horizontal');
98
+ const convertedMinWidth = removeUnit(props.minWidth, 'horizontal');
99
+ if (convertedWidth < convertedMinWidth) {
100
+ console.warn('Since width is less than min-width, it is replaced by min-width.');
101
+ basePosition.width = numberToUnit(props.minWidth);
102
+ } else {
103
+ basePosition.width = numberToUnit(props.width);
104
+ }
105
+
106
+ const convertedHeight = removeUnit(props.height, 'vertical');
107
+ const convertedMinHeight = removeUnit(props.minHeight, 'vertical');
108
+ if (convertedHeight < convertedMinHeight) {
109
+ console.warn('Since height is less than min-height, it is replaced by min-height.');
110
+ basePosition.height = numberToUnit(props.minHeight);
111
+ } else {
112
+ basePosition.height = numberToUnit(props.height);
113
+ }
114
+
115
+ basePosition.top = `calc((100% - ${basePosition.height}) / 2)`;
116
+ basePosition.left = `calc((100% - ${basePosition.width}) / 2)`;
117
+
118
+ if (removeUnit(props.width, 'horizontal') > window.innerWidth) {
119
+ basePosition.left = 0;
120
+ }
121
+ if (removeUnit(props.height, 'vertical') > window.innerHeight) {
122
+ basePosition.top = 0;
123
+ }
124
+ };
125
+
126
+ // close window
127
+ const closeWin = (from) => {
128
+ if (from === 'layer' && !props.closeOnClickModal) {
129
+ return;
130
+ }
131
+ emit('update:visible', false);
132
+ };
133
+
134
+ const changeBodyCls = (isVisible) => {
135
+ const hideScrollWindowCnt = root?.getElementsByClassName('scroll-lock')?.length;
136
+ const bodyElem = document.body;
137
+
138
+ if (isVisible) { // window open
139
+ if (props.hideScroll) {
140
+ // hideScroll 시, body 우측 padding 추가 & overflow hidden class 추가
141
+ if (!hideScrollWindowCnt) {
142
+ const scrollWidth = getVScrollWidth();
143
+ bodyElem.style.paddingRight = `${scrollWidth}px`;
144
+ }
145
+ bodyElem.classList.add('ev-window-scroll-lock');
146
+ }
147
+ } else if (props.hideScroll && hideScrollWindowCnt === 1) { // window close
148
+ bodyElem.style.removeProperty('padding-right');
149
+ bodyElem.classList.remove('ev-window-scroll-lock');
150
+ }
151
+ };
152
+
153
+ setBasePosition();
154
+
155
+ watch(
156
+ () => props.visible,
157
+ async (newVal) => {
158
+ changeBodyCls(newVal);
159
+ if (newVal) {
160
+ await nextTick(() => {
161
+ setBasePosition();
162
+ });
163
+ }
164
+ },
165
+ );
166
+
167
+ return {
168
+ windowRef,
169
+ headerRef,
170
+ isFullExpandWindow,
171
+ maximizableIcon,
172
+ baseStyle,
173
+ closeWin,
174
+ numberToUnit,
175
+ removeUnit,
176
+ };
177
+ };
178
+
179
+ const useMouseEvent = (param) => {
180
+ const { props, emit } = getCurrentInstance();
181
+ const {
182
+ windowRef,
183
+ headerRef,
184
+ isFullExpandWindow,
185
+ numberToUnit,
186
+ removeUnit,
187
+ } = param;
188
+
189
+ const draggingMinSize = 50;
190
+ const grabbingBorderSize = 5;
191
+ const dragStyle = reactive({});
192
+ const clickedInfo = reactive({
193
+ state: '',
194
+ pressedSpot: '',
195
+ top: 0,
196
+ left: 0,
197
+ width: 0,
198
+ height: 0,
199
+ clientX: 0,
200
+ clientY: 0,
201
+ });
202
+ const draggedInfo = reactive({
203
+ top: 0,
204
+ left: 0,
205
+ });
206
+ const grabbingBorderPosInfo = reactive({
207
+ top: false,
208
+ right: false,
209
+ left: false,
210
+ bottom: false,
211
+ });
212
+ const beforeExpandPosInfo = reactive({
213
+ width: null,
214
+ height: null,
215
+ top: null,
216
+ left: null,
217
+ });
218
+
219
+ const isInHeader = (x, y) => {
220
+ if (x == null || y == null) {
221
+ return false;
222
+ }
223
+
224
+ const rect = windowRef.value.getBoundingClientRect();
225
+ const posX = +x - rect.left;
226
+ const posY = +y - rect.top;
227
+ const headerAreaStyleInfo = headerRef.value.style;
228
+ const headerPaddingInfo = {
229
+ top: removeUnit(headerAreaStyleInfo.paddingTop, 'vertical'),
230
+ left: removeUnit(headerAreaStyleInfo.paddingLeft, 'horizontal'),
231
+ right: removeUnit(headerAreaStyleInfo.paddingRight, 'horizontal'),
232
+ };
233
+ const startPosX = headerPaddingInfo.left;
234
+ const endPosX = rect.width - headerPaddingInfo.right;
235
+ const startPosY = headerPaddingInfo.top;
236
+ const endPosY = startPosY + headerRef.value.offsetHeight;
237
+
238
+ return posX > startPosX && posX < endPosX && posY > startPosY && posY < endPosY;
239
+ };
240
+
241
+ const setDragStyle = (paramObj) => {
242
+ if (paramObj === null || typeof paramObj !== 'object') {
243
+ return;
244
+ }
245
+
246
+ let top;
247
+ let left;
248
+ let width;
249
+ let height;
250
+ let tMinWidth;
251
+ let tMinHeight;
252
+ const windowEl = windowRef.value;
253
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
254
+
255
+ if (hasOwnProperty.call(paramObj, 'top')) {
256
+ top = paramObj.top;
257
+ } else {
258
+ top = clickedInfo.top;
259
+ }
260
+
261
+ if (hasOwnProperty.call(paramObj, 'left')) {
262
+ left = paramObj.left;
263
+ } else {
264
+ left = clickedInfo.left;
265
+ }
266
+
267
+ if (hasOwnProperty.call(paramObj, 'width')) {
268
+ width = paramObj.width;
269
+ } else {
270
+ width = windowEl.offsetWidth;
271
+ }
272
+
273
+ if (hasOwnProperty.call(paramObj, 'height')) {
274
+ height = paramObj.height;
275
+ } else {
276
+ height = windowEl.offsetHeight;
277
+ }
278
+
279
+ if (hasOwnProperty.call(paramObj, 'minWidth')) {
280
+ tMinWidth = paramObj.minWidth;
281
+ } else {
282
+ tMinWidth = props.minWidth;
283
+ }
284
+
285
+ if (hasOwnProperty.call(paramObj, 'minHeight')) {
286
+ tMinHeight = paramObj.minHeight;
287
+ } else {
288
+ tMinHeight = props.minHeight;
289
+ }
290
+
291
+ width = removeUnit(width, 'horizontal') > removeUnit(tMinWidth, 'horizontal') ? width : tMinWidth;
292
+ height = removeUnit(height, 'vertical') > removeUnit(tMinHeight, 'vertical') ? height : tMinHeight;
293
+
294
+ dragStyle.top = numberToUnit(top);
295
+ dragStyle.left = numberToUnit(left);
296
+ dragStyle.width = numberToUnit(width);
297
+ dragStyle.height = numberToUnit(height);
298
+ dragStyle.minWidth = numberToUnit(tMinWidth);
299
+ dragStyle.minHeight = numberToUnit(tMinHeight);
300
+ };
301
+
302
+ const changeMouseCursor = (e) => {
303
+ if (!windowRef.value || clickedInfo.pressedSpot) {
304
+ return;
305
+ }
306
+
307
+ if (props.resizable) {
308
+ const rect = windowRef.value.getBoundingClientRect();
309
+ const x = e.clientX - rect.left;
310
+ const y = e.clientY - rect.top;
311
+ const top = y < grabbingBorderSize;
312
+ const left = x < grabbingBorderSize;
313
+ const right = x >= (rect.width - grabbingBorderSize);
314
+ const bottom = y >= (rect.height - grabbingBorderSize);
315
+
316
+ if ((top && left) || (bottom && right)) {
317
+ windowRef.value.style.cursor = 'nwse-resize';
318
+ } else if ((top && right) || (bottom && left)) {
319
+ windowRef.value.style.cursor = 'nesw-resize';
320
+ } else if (right || left) {
321
+ windowRef.value.style.cursor = 'ew-resize';
322
+ } else if (bottom || top) {
323
+ windowRef.value.style.cursor = 'ns-resize';
324
+ } else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
325
+ windowRef.value.style.cursor = 'move';
326
+ } else {
327
+ windowRef.value.style.cursor = 'default';
328
+ }
329
+ } else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
330
+ windowRef.value.style.cursor = 'move';
331
+ } else {
332
+ windowRef.value.style.cursor = 'default';
333
+ }
334
+ };
335
+
336
+ // window resize
337
+ const resizeWindow = (e) => {
338
+ const windowWidth = window.innerWidth;
339
+ const windowHeight = window.innerHeight;
340
+ const isTop = grabbingBorderPosInfo.top;
341
+ const isLeft = grabbingBorderPosInfo.left;
342
+ const isRight = grabbingBorderPosInfo.right;
343
+ const isBottom = grabbingBorderPosInfo.bottom;
344
+ const minWidth = removeUnit(props.minWidth, 'horizontal');
345
+ const minHeight = removeUnit(props.minHeight, 'vertical');
346
+ const clientX = e.clientX >= windowWidth ? windowWidth : e.clientX;
347
+ let clientY = e.clientY >= windowHeight ? windowHeight : e.clientY;
348
+ clientY = e.clientY > 0 ? clientY : 0;
349
+ const diffX = clientX - clickedInfo.clientX;
350
+ const diffY = clientY - clickedInfo.clientY;
351
+
352
+ let top = clickedInfo.top;
353
+ let left = clickedInfo.left;
354
+ let width = clickedInfo.width;
355
+ let height = clickedInfo.height;
356
+ const maxTop = (top + clickedInfo.height) - minHeight;
357
+ const maxLeft = (left + clickedInfo.width) - minWidth;
358
+
359
+ if (isTop) {
360
+ top = clickedInfo.top + diffY;
361
+ height = clickedInfo.height - diffY;
362
+
363
+ if (top > maxTop) {
364
+ top = maxTop;
365
+ }
366
+ }
367
+
368
+ if (isLeft) {
369
+ left = clickedInfo.left + diffX;
370
+ width = clickedInfo.width - diffX;
371
+
372
+ if (left > maxLeft) {
373
+ left = maxLeft;
374
+ }
375
+ }
376
+
377
+ if (isRight) {
378
+ width = clickedInfo.width + diffX;
379
+ }
380
+
381
+ if (isBottom) {
382
+ height = clickedInfo.height + diffY;
383
+ }
384
+
385
+ width = Math.min(Math.max(width, minWidth), windowWidth);
386
+ height = Math.min(Math.max(height, minHeight), windowHeight);
387
+
388
+ const positionInfo = { top, left, width, height };
389
+ setDragStyle(positionInfo);
390
+ emit('resize', e, { ...positionInfo });
391
+ };
392
+
393
+ // 브라우저 상하 위치 제약
394
+ const getValidTop = (windowHeight, top) => {
395
+ let tempTop = top;
396
+
397
+ if (tempTop < 0) { // 상
398
+ tempTop = 0;
399
+ } else if (tempTop > windowHeight - draggingMinSize) { // 하
400
+ tempTop = Math.floor(windowHeight - draggingMinSize);
401
+ }
402
+ return tempTop;
403
+ };
404
+ // 브라우저 좌우 위치 제약
405
+ const getValidLeft = (windowWidth, left) => {
406
+ let tempLeft = left;
407
+ if (tempLeft < -(clickedInfo.width - draggingMinSize)) { // 좌
408
+ tempLeft = -Math.floor(clickedInfo.width - draggingMinSize);
409
+ } else if (tempLeft > windowWidth - draggingMinSize) { // 우
410
+ tempLeft = Math.floor(windowWidth - draggingMinSize);
411
+ }
412
+ return tempLeft;
413
+ };
414
+
415
+ // mousedown > mousemove: 마우스 드래그
416
+ const dragging = (e) => {
417
+ e.preventDefault();
418
+ clickedInfo.state = 'mousedown-mousemove';
419
+
420
+ // window header를 통해 mouseMove 됐을 경우
421
+ if (props.draggable && clickedInfo.pressedSpot === 'header') {
422
+ const windowWidth = document.documentElement.clientWidth;
423
+ const windowHeight = document.documentElement.clientHeight;
424
+ const diffTop = e.clientY - clickedInfo.clientY;
425
+ const diffLeft = e.clientX - clickedInfo.clientX;
426
+
427
+ let tempTop = clickedInfo.top + diffTop;
428
+ let tempLeft = clickedInfo.left + diffLeft;
429
+
430
+ tempTop = getValidTop(windowHeight, tempTop);
431
+ tempLeft = getValidLeft(windowWidth, tempLeft);
432
+
433
+ setDragStyle({
434
+ top: `${tempTop}px`,
435
+ left: `${tempLeft}px`,
436
+ width: dragStyle.width ?? props.width,
437
+ height: dragStyle.height ?? props.height,
438
+ });
439
+ } else if (props.resizable && clickedInfo.pressedSpot === 'border') {
440
+ resizeWindow(e);
441
+ }
442
+
443
+ emit('mousedown-mousemove', e);
444
+ };
445
+
446
+ // mousedown > mouseup: 마우스 드래그 종료
447
+ const endDrag = (e) => {
448
+ clickedInfo.state = '';
449
+ clickedInfo.pressedSpot = '';
450
+
451
+ emit('mousedown-mouseup', e);
452
+
453
+ window.removeEventListener('mousemove', dragging);
454
+ window.removeEventListener('mouseup', endDrag);
455
+ };
456
+
457
+ // mousedown: 드래그 시작
458
+ const startDrag = (e) => {
459
+ if (!windowRef.value || (!props.resizable && !props.draggable)) {
460
+ return;
461
+ }
462
+ let pressedSpot = '';
463
+ if (props.resizable) {
464
+ const clientRect = windowRef.value.getBoundingClientRect();
465
+ const x = e.clientX - clientRect.left;
466
+ const y = e.clientY - clientRect.top;
467
+ const isGrabTop = y < grabbingBorderSize;
468
+ const isGrabLeft = x < grabbingBorderSize;
469
+ const isGrabRight = x >= (clientRect.width - grabbingBorderSize);
470
+ const isGrabBottom = y >= (clientRect.height - grabbingBorderSize);
471
+
472
+ grabbingBorderPosInfo.top = isGrabTop;
473
+ grabbingBorderPosInfo.left = isGrabLeft;
474
+ grabbingBorderPosInfo.right = isGrabRight;
475
+ grabbingBorderPosInfo.bottom = isGrabBottom;
476
+
477
+ if (isGrabTop || isGrabLeft || isGrabRight || isGrabBottom) {
478
+ pressedSpot = 'border';
479
+ }
480
+ }
481
+
482
+ if (pressedSpot !== 'border' && isInHeader(e.clientX, e.clientY)) {
483
+ pressedSpot = 'header';
484
+ }
485
+
486
+ if (!pressedSpot
487
+ || (!props.draggable && pressedSpot === 'header')
488
+ || (!props.resizable && pressedSpot === 'border')
489
+ ) {
490
+ return;
491
+ }
492
+
493
+ clickedInfo.state = 'mousedown';
494
+ clickedInfo.pressedSpot = pressedSpot;
495
+ clickedInfo.top = windowRef.value.offsetTop;
496
+ clickedInfo.left = windowRef.value.offsetLeft;
497
+ clickedInfo.width = windowRef.value.offsetWidth;
498
+ clickedInfo.height = windowRef.value.offsetHeight;
499
+ clickedInfo.clientX = e.clientX;
500
+ clickedInfo.clientY = e.clientY;
501
+
502
+ emit('mousedown', { ...clickedInfo });
503
+
504
+ window.addEventListener('mousemove', dragging);
505
+ window.addEventListener('mouseup', endDrag);
506
+ };
507
+
508
+ const moveMouse = (e) => {
509
+ if (!props.draggable && !props.resizable) {
510
+ return;
511
+ }
512
+ changeMouseCursor(e);
513
+ };
514
+
515
+ const clickExpandBtn = () => {
516
+ isFullExpandWindow.value = !isFullExpandWindow.value;
517
+ nextTick(() => {
518
+ if (isFullExpandWindow.value) {
519
+ beforeExpandPosInfo.top = windowRef.value.offsetTop;
520
+ beforeExpandPosInfo.left = windowRef.value.offsetLeft;
521
+ beforeExpandPosInfo.width = windowRef.value.offsetWidth;
522
+ beforeExpandPosInfo.height = windowRef.value.offsetHeight;
523
+
524
+ setDragStyle({
525
+ top: 0,
526
+ left: 0,
527
+ width: document.body.clientWidth,
528
+ height: document.body.clientHeight,
529
+ });
530
+ } else {
531
+ setDragStyle({
532
+ top: beforeExpandPosInfo.top,
533
+ left: beforeExpandPosInfo.left,
534
+ width: beforeExpandPosInfo.width,
535
+ height: beforeExpandPosInfo.height,
536
+ });
537
+ }
538
+
539
+ emit('expand', {
540
+ top: beforeExpandPosInfo.top,
541
+ left: beforeExpandPosInfo.left,
542
+ width: beforeExpandPosInfo.width,
543
+ height: beforeExpandPosInfo.height,
544
+ });
545
+ });
546
+ };
547
+
548
+ const initWindowInfo = () => {
549
+ isFullExpandWindow.value = false;
550
+
551
+ clickedInfo.state = '';
552
+ clickedInfo.pressedSpot = '';
553
+ clickedInfo.top = 0;
554
+ clickedInfo.left = 0;
555
+ clickedInfo.width = 0;
556
+ clickedInfo.height = 0;
557
+ clickedInfo.clientX = 0;
558
+ clickedInfo.clientY = 0;
559
+
560
+ draggedInfo.top = 0;
561
+ draggedInfo.left = 0;
562
+
563
+ grabbingBorderPosInfo.top = false;
564
+ grabbingBorderPosInfo.left = false;
565
+ grabbingBorderPosInfo.right = false;
566
+ grabbingBorderPosInfo.bottom = false;
567
+
568
+ beforeExpandPosInfo.top = null;
569
+ beforeExpandPosInfo.left = null;
570
+ beforeExpandPosInfo.width = null;
571
+ beforeExpandPosInfo.height = null;
572
+
573
+ Object.keys(dragStyle).forEach((key) => {
574
+ delete dragStyle[key];
575
+ });
576
+ };
577
+
578
+ watch(
579
+ () => props.visible,
580
+ (newVal) => {
581
+ if (!newVal) {
582
+ initWindowInfo();
583
+ }
584
+ },
585
+ );
586
+
587
+ return {
588
+ dragStyle,
589
+ startDrag,
590
+ moveMouse,
591
+ clickExpandBtn,
592
+ };
593
+ };
594
+
595
+ const activeWindows = (() => {
596
+ let windows = [];
597
+ let sequence = 0;
598
+
599
+ return {
600
+ add(activeWindow) {
601
+ if (activeWindow === null || activeWindow === undefined) return;
602
+
603
+ activeWindow.sequence = sequence++;
604
+ windows.push(activeWindow);
605
+
606
+ // eslint-disable-next-line consistent-return
607
+ return activeWindow.sequence;
608
+ },
609
+ remove(inactiveWindow) {
610
+ if (inactiveWindow === null || inactiveWindow === undefined) return;
611
+ windows = windows.filter(activeWindow => activeWindow.sequence !== inactiveWindow.sequence);
612
+ },
613
+
614
+ get windows() {
615
+ return windows.slice();
616
+ },
617
+ getWindowBySequence(targetSequence) {
618
+ return windows.find(activeWindow => activeWindow.sequence === targetSequence);
619
+ },
620
+
621
+ isEmpty() {
622
+ return windows.length <= 0;
623
+ },
624
+ isFirstWindowOpen() {
625
+ return sequence === 1;
626
+ },
627
+ };
628
+ })();
629
+
630
+ const zIndexService = (() => {
631
+ const LOWER = 700;
632
+ const UPPER = 750;
633
+
634
+ const INCREMENT = 1;
635
+ const PADDING = INCREMENT * 2;
636
+
637
+ const UPPER_LIMIT = UPPER - PADDING;
638
+
639
+ let current = LOWER;
640
+
641
+ return {
642
+ getNext() {
643
+ if (current >= UPPER_LIMIT) {
644
+ return UPPER_LIMIT;
645
+ }
646
+ current += INCREMENT;
647
+ return current;
648
+ },
649
+ getNextOverLimit() {
650
+ return UPPER_LIMIT + INCREMENT;
651
+ },
652
+ getPrevFrom(index) {
653
+ const prev = current - (index * INCREMENT);
654
+
655
+ if (prev <= LOWER) return LOWER;
656
+ return prev;
657
+ },
658
+ isUpperLimitClose() {
659
+ return current >= UPPER_LIMIT;
660
+ },
661
+ resetToLower() {
662
+ current = LOWER;
663
+ },
664
+ getAllocableCount() {
665
+ return Math.floor((UPPER_LIMIT - LOWER) / INCREMENT);
666
+ },
667
+ };
668
+ })();
669
+
670
+ const getZIndexFromElement = (element) => {
671
+ const zIndex = window.getComputedStyle(element).getPropertyValue('z-index').trim();
672
+
673
+ if (!zIndex || isNaN(zIndex)) return 700; // window 초기 z-index 값
674
+
675
+ return parseInt(zIndex);
676
+ };
677
+
678
+ const getActiveWindowsOrderByZIndexAsc = () => {
679
+ // zIndex 클수록, 최근에 열린 것일수록(sequence 클수록) 뒤에 위치
680
+ const compareByZIndex = (window1, window2) => {
681
+ if (window1.zIndex > window2.zIndex) return 1;
682
+ if (window1.zIndex < window2.zIndex) return -1;
683
+
684
+ if (window1.sequence > window2.sequence) return 1;
685
+ return -1;
686
+ };
687
+
688
+ const activeWindowsSorted = Array.prototype.map.call(activeWindows.windows, activeWindow => ({
689
+ ...activeWindow,
690
+ zIndex: getZIndexFromElement(activeWindow.elem),
691
+ })).sort(compareByZIndex);
692
+
693
+ return activeWindowsSorted;
694
+ };
695
+
696
+ const useEscCloseAndFocusable = ({ closeWin, windowRef }) => {
697
+ const { props } = getCurrentInstance();
698
+
699
+ let sequence = null;
700
+ let timer = null;
701
+
702
+ // escClose 관련 로직 시작
703
+ const addActiveWindow = () => {
704
+ const windowSequence = activeWindows.add({
705
+ sequence,
706
+ closeWin,
707
+ elem: windowRef.value,
708
+ escClose: props.escClose,
709
+ });
710
+ return windowSequence;
711
+ };
712
+
713
+ const removeInactiveWindow = (inactiveWindow) => {
714
+ activeWindows.remove(inactiveWindow);
715
+ };
716
+
717
+ const keydownEsc = (event) => {
718
+ if (activeWindows.isEmpty()) return;
719
+
720
+ const { code } = event;
721
+ if (code !== 'Escape') return;
722
+
723
+ const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
724
+ const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
725
+
726
+ // 예시 상황) Nested에서 외부 Window의 escClose는 true이고, 내부 Window의 escClose는 false인 경우,
727
+ // esc 눌러도 외부 Window는 닫히지 않고, 가장 상단에 있는 내부 Window가 수동으로 닫힌 후에 닫히도록 하기 위해
728
+ if (!topActiveWindow.escClose) return;
729
+
730
+ topActiveWindow.closeWin();
731
+ };
732
+
733
+ const setWindowActive = () => {
734
+ sequence = addActiveWindow();
735
+ // DOM의 dataset에 sequence 값 추가해 식별 가능하도록
736
+ windowRef.value.dataset.sequence = sequence;
737
+
738
+ if (activeWindows.isFirstWindowOpen()) {
739
+ document.addEventListener('keydown', keydownEsc);
740
+ }
741
+ };
742
+
743
+ const setWindowInactive = () => {
744
+ const inactiveWindow = activeWindows.getWindowBySequence(sequence);
745
+ removeInactiveWindow(inactiveWindow);
746
+ };
747
+ // escClose 관련 로직 끝
748
+
749
+
750
+ // focusable 관련 로직 시작
751
+ const setZIndexToWindow = ({ elem, zIndex }) => {
752
+ // 모달인 경우에는 dim layer도 같이 z-index 높여준다.
753
+ if (props.isModal) {
754
+ const dimLayerElem = elem.parentElement.getElementsByClassName('ev-window-dim-layer')[0];
755
+ dimLayerElem.style.zIndex = zIndex;
756
+ }
757
+
758
+ elem.style.zIndex = zIndex;
759
+ };
760
+
761
+ const assignZIndex = () => {
762
+ // Window가 1번째로 열릴 때, z-index 값을 시작값으로 설정
763
+ if (activeWindows.windows.length === 1) {
764
+ zIndexService.resetToLower();
765
+ }
766
+
767
+ const nextZIndex = zIndexService.getNext();
768
+ setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
769
+ };
770
+
771
+ const sameAsCurrent = windowData => String(windowData.sequence)
772
+ === windowRef.value.dataset.sequence;
773
+
774
+ // 할당하려는 z-index 값이 상한일 때
775
+ const reassignZIndex = () => {
776
+ const activeWindowsZIndexAsc = getActiveWindowsOrderByZIndexAsc();
777
+
778
+ const overCountLimit = activeWindows.windows.length > zIndexService.getAllocableCount();
779
+ // 할당 가능한 z-index 수보다 많은 Window를 띄웠을 때
780
+ if (overCountLimit) {
781
+ const activeWindowsZIndexDesc = activeWindowsZIndexAsc.reverse();
782
+
783
+ // z-index 기준 내림차순으로 정렬한 Window의 z-index 값을 UPPER에서 LOWER로 1씩 감소한 값 할당
784
+ let interval = 0;
785
+ activeWindowsZIndexDesc.forEach((activeWindow) => {
786
+ if (sameAsCurrent(activeWindow)) return;
787
+
788
+ const prevZIndex = zIndexService.getPrevFrom(interval++);
789
+ setZIndexToWindow({ elem: activeWindow.elem, zIndex: prevZIndex });
790
+ });
791
+
792
+ // 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
793
+ const nextZIndex = zIndexService.getNextOverLimit();
794
+ setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
795
+ } else {
796
+ zIndexService.resetToLower();
797
+
798
+ activeWindowsZIndexAsc.forEach((activeWindow) => {
799
+ if (sameAsCurrent(activeWindow)) return;
800
+
801
+ const nextZIndex = zIndexService.getNext();
802
+ setZIndexToWindow({ elem: activeWindow.elem, zIndex: nextZIndex });
803
+ });
804
+
805
+ // 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
806
+ const nextZIndex = zIndexService.getNext();
807
+ setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
808
+ }
809
+ };
810
+
811
+ const checkLimitAndSetZIndex = () => {
812
+ if (zIndexService.isUpperLimitClose()) {
813
+ reassignZIndex();
814
+ } else {
815
+ assignZIndex();
816
+ }
817
+ };
818
+
819
+ const setFocus = () => {
820
+ // X 버튼을 클릭했을 때
821
+ if (!windowRef.value) return;
822
+
823
+ // focusable prop이 false인 경우에는 z-index를 높이지 않는다.
824
+ if (!props.focusable) return;
825
+
826
+ const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
827
+ const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
828
+
829
+ const isAlreadyTop = sameAsCurrent(topActiveWindow);
830
+ if (isAlreadyTop) return;
831
+
832
+ checkLimitAndSetZIndex();
833
+ };
834
+ // focusable 관련 로직 끝
835
+
836
+
837
+ /*
838
+ 실행 시점(=Window 열림):
839
+ visible 초기값이 true일 때 watch를 실행시키지 않아 onMounted hook 사용
840
+ */
841
+ onMounted(() => {
842
+ if (props.visible) {
843
+ setWindowActive();
844
+ timer = setTimeout(checkLimitAndSetZIndex, 0);
845
+ }
846
+ });
847
+
848
+ /*
849
+ 실행 시점(=Window 닫힘):
850
+ 예시. 배열을 통해 Window 여러 개 띄울 때, 배열 원소 삭제로 인해 해당 Window가 닫히는 경우
851
+ unmount가 발생해서 watch를 실행히시키지 않아 onBeforeUnmount hook 사용
852
+ */
853
+ onBeforeUnmount(() => {
854
+ if (props.visible) {
855
+ setWindowInactive();
856
+ clearTimeout(timer);
857
+ }
858
+ });
859
+
860
+ /*
861
+ 실행 시점:
862
+ 1. visible 값이 false -> true로 변했을 때(=Window 열림)
863
+ 2. visible 값이 true -> false로 변했을 때(=Window 닫힙)
864
+ */
865
+ watch(
866
+ () => props.visible,
867
+ (visible) => {
868
+ nextTick(() => {
869
+ if (visible) {
870
+ // visible 값이 false -> true로 변경되었을 때
871
+ setWindowActive();
872
+ timer = setTimeout(checkLimitAndSetZIndex, 0);
873
+ } else {
874
+ // visible 값이 true -> false로 변경되었을 때
875
+ setWindowInactive();
876
+ clearTimeout(timer);
877
+ }
878
+ });
879
+ });
880
+
881
+ watch(
882
+ () => props.escClose,
883
+ (escClose) => {
884
+ if (!props.visible) return;
885
+ const currentWindow = activeWindows.getWindowBySequence(sequence);
886
+ if (currentWindow) currentWindow.escClose = escClose;
887
+ },
888
+ );
889
+
890
+ return {
891
+ setFocus,
892
+ };
893
+ };
894
+
895
+ export {
896
+ useModel,
897
+ useMouseEvent,
898
+ useEscCloseAndFocusable,
899
+ };