js-kompo-utils 1.0.20 → 1.0.22
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.
- package/components/VlDropdown.vue +15 -21
- package/components/VlSelect.vue +82 -25
- package/package.json +1 -1
|
@@ -63,6 +63,9 @@ export default {
|
|
|
63
63
|
shouldShowMenu(visible) {
|
|
64
64
|
if (visible) {
|
|
65
65
|
this.updatePosition()
|
|
66
|
+
this.attachListeners()
|
|
67
|
+
} else {
|
|
68
|
+
this.detachListeners()
|
|
66
69
|
}
|
|
67
70
|
if (!visible && this.openOnClick) {
|
|
68
71
|
this.open = false
|
|
@@ -147,11 +150,10 @@ export default {
|
|
|
147
150
|
},
|
|
148
151
|
mounted() {
|
|
149
152
|
this.teleportMenu()
|
|
150
|
-
this.setupListeners()
|
|
151
153
|
},
|
|
152
154
|
beforeDestroy() {
|
|
153
155
|
this.cleanupMenu()
|
|
154
|
-
this.
|
|
156
|
+
this.detachListeners()
|
|
155
157
|
},
|
|
156
158
|
methods:{
|
|
157
159
|
teleportMenu() {
|
|
@@ -159,7 +161,7 @@ export default {
|
|
|
159
161
|
const root = this.$refs.dropdownRoot
|
|
160
162
|
if (!menu) return
|
|
161
163
|
|
|
162
|
-
this.inModal = !!(root && root.closest('.kompoModal'))
|
|
164
|
+
this.inModal = !!(root && root.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l'))
|
|
163
165
|
|
|
164
166
|
// Transfer scroll styles from root before teleporting
|
|
165
167
|
if (root && root.classList.contains('dropdown-with-scroll')) {
|
|
@@ -182,27 +184,19 @@ export default {
|
|
|
182
184
|
clearTimeout(this._closeTimeout)
|
|
183
185
|
}
|
|
184
186
|
},
|
|
185
|
-
|
|
186
|
-
this.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
this._resizeHandler = () => {
|
|
192
|
-
if (this.shouldShowMenu) {
|
|
193
|
-
this.updatePosition()
|
|
194
|
-
}
|
|
195
|
-
}
|
|
187
|
+
attachListeners() {
|
|
188
|
+
if (this._listenersAttached) return
|
|
189
|
+
this._scrollHandler = () => requestAnimationFrame(() => this.updatePosition())
|
|
190
|
+
this._resizeHandler = () => this.updatePosition()
|
|
196
191
|
window.addEventListener('scroll', this._scrollHandler, true)
|
|
197
192
|
window.addEventListener('resize', this._resizeHandler, { passive: true })
|
|
193
|
+
this._listenersAttached = true
|
|
198
194
|
},
|
|
199
|
-
|
|
200
|
-
if (this.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
window.removeEventListener('resize', this._resizeHandler)
|
|
205
|
-
}
|
|
195
|
+
detachListeners() {
|
|
196
|
+
if (!this._listenersAttached) return
|
|
197
|
+
window.removeEventListener('scroll', this._scrollHandler, true)
|
|
198
|
+
window.removeEventListener('resize', this._resizeHandler)
|
|
199
|
+
this._listenersAttached = false
|
|
206
200
|
},
|
|
207
201
|
updatePosition() {
|
|
208
202
|
const root = this.$refs.dropdownRoot
|
package/components/VlSelect.vue
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
<vlTaggableInput
|
|
4
4
|
v-click-out="blur"
|
|
5
5
|
v-bind="$_taggableInputAttributes"
|
|
6
|
-
v-on="$_taggableInputEvents"
|
|
6
|
+
v-on="$_taggableInputEvents"
|
|
7
|
+
ref="taggableInput">
|
|
7
8
|
<template v-slot:prepend v-if="$_icon">
|
|
8
9
|
<div v-bind="prependIcon" />
|
|
9
10
|
</template>
|
|
@@ -21,11 +22,11 @@
|
|
|
21
22
|
<div v-html="appendIcon"/>
|
|
22
23
|
</template>
|
|
23
24
|
</vlTaggableInput>
|
|
24
|
-
<div class="vlOptions"
|
|
25
|
+
<div class="vlOptions vlOptionsTeleported"
|
|
25
26
|
:key="optionsKey"
|
|
26
27
|
ref="selectOptions"
|
|
27
28
|
:style="optionsStyle"
|
|
28
|
-
:class="{ 'vlOptionsFlipUp': flipUp }">
|
|
29
|
+
:class="{ 'vlOptionsFlipUp': flipUp, 'vlOptionsVisible': isFocused }">
|
|
29
30
|
<template v-if="filteredOptions.length">
|
|
30
31
|
<div v-for="(option,key) in filteredOptions" :key="option.value" :ref="key"
|
|
31
32
|
class="vlOption"
|
|
@@ -58,6 +59,7 @@ export default {
|
|
|
58
59
|
data() {
|
|
59
60
|
return {
|
|
60
61
|
flipUp: false,
|
|
62
|
+
panelStyle: null,
|
|
61
63
|
}
|
|
62
64
|
},
|
|
63
65
|
computed: {
|
|
@@ -68,43 +70,98 @@ export default {
|
|
|
68
70
|
return !!this.$_config('openUpward')
|
|
69
71
|
},
|
|
70
72
|
optionsStyle() {
|
|
71
|
-
if (!this.
|
|
72
|
-
return
|
|
73
|
-
top: 'auto',
|
|
74
|
-
bottom: '100%',
|
|
75
|
-
borderRadius: '5px 5px 0 0',
|
|
76
|
-
}
|
|
73
|
+
if (!this.isFocused || !this.panelStyle) return { display: 'none' }
|
|
74
|
+
return this.panelStyle
|
|
77
75
|
},
|
|
78
76
|
},
|
|
79
77
|
watch: {
|
|
80
78
|
isFocused(focused) {
|
|
81
79
|
if (focused) {
|
|
82
|
-
this.$nextTick(() => this.
|
|
80
|
+
this.$nextTick(() => this.refresh())
|
|
81
|
+
this.attachListeners()
|
|
83
82
|
} else {
|
|
84
83
|
this.flipUp = false
|
|
84
|
+
this.panelStyle = null
|
|
85
|
+
this.detachListeners()
|
|
85
86
|
}
|
|
86
87
|
},
|
|
87
88
|
filteredOptions() {
|
|
88
|
-
if (this.isFocused)
|
|
89
|
-
this.$nextTick(() => this.computeFlip())
|
|
90
|
-
}
|
|
89
|
+
if (this.isFocused) this.$nextTick(() => this.refresh())
|
|
91
90
|
},
|
|
92
91
|
},
|
|
92
|
+
mounted() {
|
|
93
|
+
this.teleportOptions()
|
|
94
|
+
},
|
|
95
|
+
beforeDestroy() {
|
|
96
|
+
this.cleanupOptions()
|
|
97
|
+
this.detachListeners()
|
|
98
|
+
},
|
|
93
99
|
methods: {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
teleportOptions() {
|
|
101
|
+
const opts = this.$refs.selectOptions
|
|
102
|
+
if (opts && opts.parentNode !== document.body) {
|
|
103
|
+
document.body.appendChild(opts)
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
cleanupOptions() {
|
|
107
|
+
const opts = this.$refs.selectOptions
|
|
108
|
+
if (opts && opts.parentNode === document.body) {
|
|
109
|
+
document.body.removeChild(opts)
|
|
98
110
|
}
|
|
111
|
+
},
|
|
112
|
+
anchorEl() {
|
|
113
|
+
return this.$refs.taggableInput?.$el || this.$refs.input?.parentElement
|
|
114
|
+
},
|
|
115
|
+
attachListeners() {
|
|
116
|
+
if (this._listenersAttached) return
|
|
117
|
+
this._onScroll = (e) => {
|
|
118
|
+
const opts = this.$refs.selectOptions
|
|
119
|
+
if (opts && e.target instanceof Node && opts.contains(e.target)) return
|
|
120
|
+
this.blur()
|
|
121
|
+
}
|
|
122
|
+
this._onResize = () => this.refresh()
|
|
123
|
+
window.addEventListener('scroll', this._onScroll, true)
|
|
124
|
+
window.addEventListener('resize', this._onResize, { passive: true })
|
|
125
|
+
this._listenersAttached = true
|
|
126
|
+
},
|
|
127
|
+
detachListeners() {
|
|
128
|
+
if (!this._listenersAttached) return
|
|
129
|
+
window.removeEventListener('scroll', this._onScroll, true)
|
|
130
|
+
window.removeEventListener('resize', this._onResize)
|
|
131
|
+
this._listenersAttached = false
|
|
132
|
+
},
|
|
133
|
+
refresh() {
|
|
99
134
|
const opts = this.$refs.selectOptions
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
135
|
+
const anchor = this.anchorEl()
|
|
136
|
+
if (!opts || !anchor) return
|
|
137
|
+
|
|
138
|
+
const rect = anchor.getBoundingClientRect()
|
|
139
|
+
const inOverlay = !!anchor.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l')
|
|
140
|
+
const baseStyle = {
|
|
141
|
+
position: 'fixed',
|
|
142
|
+
left: rect.left + 'px',
|
|
143
|
+
width: rect.width + 'px',
|
|
144
|
+
zIndex: inOverlay ? 5001 : 1000,
|
|
145
|
+
top: rect.bottom + 'px',
|
|
146
|
+
bottom: 'auto',
|
|
147
|
+
}
|
|
148
|
+
this.panelStyle = baseStyle
|
|
149
|
+
|
|
150
|
+
this.$nextTick(() => {
|
|
151
|
+
const optsHeight = opts.offsetHeight
|
|
152
|
+
const spaceBelow = window.innerHeight - rect.bottom
|
|
153
|
+
const spaceAbove = rect.top
|
|
154
|
+
const shouldFlip = this.forceUp || (spaceBelow < optsHeight && spaceAbove > spaceBelow)
|
|
155
|
+
this.flipUp = shouldFlip
|
|
156
|
+
if (shouldFlip) {
|
|
157
|
+
this.panelStyle = {
|
|
158
|
+
...baseStyle,
|
|
159
|
+
top: 'auto',
|
|
160
|
+
bottom: (window.innerHeight - rect.top) + 'px',
|
|
161
|
+
borderRadius: '5px 5px 0 0',
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
108
165
|
},
|
|
109
166
|
},
|
|
110
167
|
}
|