Skip to content

Commit 433118a

Browse files
committed
feat: positioningDisabled + mobile example
1 parent 13dfd26 commit 433118a

File tree

6 files changed

+251
-39
lines changed

6 files changed

+251
-39
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<script>
2+
let count = 0
3+
4+
export default {
5+
data () {
6+
return {
7+
isMobile: false,
8+
}
9+
},
10+
11+
methods: {
12+
onShow () {
13+
if (count === 0) {
14+
document.body.classList.add('no-scroll')
15+
}
16+
count++
17+
},
18+
19+
onHide () {
20+
count--
21+
if (count === 0) {
22+
document.body.classList.remove('no-scroll')
23+
}
24+
},
25+
},
26+
}
27+
</script>
28+
29+
<template>
30+
<div class="example flex flex-col items-center justify-center space-y-6">
31+
<label>
32+
<input
33+
v-model="isMobile"
34+
type="checkbox"
35+
>
36+
Is mobile
37+
</label>
38+
39+
<VDropdown
40+
:positioning-disabled="isMobile"
41+
@apply-show="isMobile && onShow()"
42+
@apply-hide="isMobile && onHide()"
43+
>
44+
<button class="border border-gray-300 rounded px-4 py-2">
45+
Click me
46+
</button>
47+
48+
<template #popper="{ hide }">
49+
<div class="p-6 space-y-6">
50+
<div>This is awesome!</div>
51+
52+
<div v-if="isMobile">
53+
<button
54+
class="bg-gray-300 rounded px-4 py-2"
55+
@click="hide()"
56+
>
57+
Cancel
58+
</button>
59+
</div>
60+
</div>
61+
</template>
62+
</VDropdown>
63+
</div>
64+
</template>
65+
66+
<style>
67+
body.no-scroll {
68+
overflow: hidden;
69+
}
70+
71+
.v-popper__popper--no-positioning {
72+
position: fixed;
73+
z-index: 9999;
74+
top: 0;
75+
left: 0;
76+
width: 100%;
77+
height: 100%;
78+
background: rgba(0 0 0 / 90%);
79+
pointer-events: none;
80+
display: flex;
81+
align-items: flex-end;
82+
padding: 12px;
83+
}
84+
85+
.v-popper__popper--no-positioning .v-popper__wrapper {
86+
width: 100%;
87+
pointer-events: auto;
88+
transition: transform .15s ease-out;
89+
}
90+
91+
.v-popper__popper--no-positioning.v-popper__popper--hidden .v-popper__wrapper {
92+
transform: translateY(100%);
93+
}
94+
95+
</style>

packages/docs/src/api/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ Hide the popper if clicked outside.
329329

330330
Boolean that disables the popper. If it was already open, it will be closed.
331331

332+
### `positioningDisabled`
333+
334+
Boolean that disables the automatic positioning of the popper. You can then style it manually. Useful for mobile version of the popper.
335+
332336
### `handleResize`
333337

334338
Boolean: Automatically update the popper position if its size changes.

packages/docs/src/guide/component.md

+110-16
Original file line numberDiff line numberDiff line change
@@ -209,22 +209,6 @@ To fix this, specify the `padding` option of the `arrow` modifier. In the follow
209209

210210
<ArrowPadding :padding="8" />
211211

212-
## Disable popper
213-
214-
Disabling a popper will prevent it from being shown.
215-
216-
```vue
217-
<VDropdown :disabled="isDisabled"></VDropdown>
218-
```
219-
220-
```js
221-
data () {
222-
return {
223-
isDisabled: true,
224-
}
225-
}
226-
```
227-
228212
## Hide from slot
229213

230214
Use the `hide` slot prop to close the popper:
@@ -281,3 +265,113 @@ Close all the poppers in the page with the `all` modifier:
281265
```vue
282266
<a v-close-popper.all>Close All</a>
283267
```
268+
269+
## Disable popper
270+
271+
Disabling a popper will prevent it from being shown.
272+
273+
```vue
274+
<VDropdown :disabled="isDisabled"></VDropdown>
275+
```
276+
277+
```js
278+
data () {
279+
return {
280+
isDisabled: true,
281+
}
282+
}
283+
```
284+
285+
## Mobile
286+
287+
You can also just disable the positioning of the popper with `positioningDisabled`:
288+
289+
```vue
290+
<VDropdown :positioning-disabled="isMobile"></VDropdown>
291+
```
292+
293+
It can for example be useful on the mobile version of your app if you want to apply a fixed position to the popper with CSS.
294+
295+
<DropdownMobileDemo />
296+
297+
```vue
298+
<script>
299+
let count = 0
300+
301+
export default {
302+
data () {
303+
return {
304+
isMobile: false,
305+
}
306+
},
307+
308+
methods: {
309+
onShow () {
310+
if (count === 0) {
311+
document.body.classList.add('no-scroll')
312+
}
313+
count++
314+
},
315+
316+
onHide () {
317+
count--
318+
if (count === 0) {
319+
document.body.classList.remove('no-scroll')
320+
}
321+
},
322+
},
323+
}
324+
</script>
325+
326+
<template>
327+
<div class="example">
328+
<label>
329+
<input v-model="isMobile" type="checkbox">
330+
Is mobile
331+
</label>
332+
333+
<VDropdown
334+
:positioning-disabled="isMobile"
335+
@apply-show="isMobile && onShow()"
336+
@apply-hide="isMobile && onHide()"
337+
>
338+
<button>Click me</button>
339+
340+
<template #popper="{ hide }">
341+
<div>This is awesome!</div>
342+
<button v-if="isMobile" @click="hide()">Cancel</button>
343+
</template>
344+
</VDropdown>
345+
</div>
346+
</template>
347+
348+
<style>
349+
body.no-scroll {
350+
overflow: hidden;
351+
}
352+
353+
.v-popper__popper--no-positioning {
354+
position: fixed;
355+
z-index: 9999;
356+
top: 0;
357+
left: 0;
358+
width: 100%;
359+
height: 100%;
360+
background: rgba(0 0 0 / 90%);
361+
pointer-events: none;
362+
display: flex;
363+
align-items: flex-end;
364+
padding: 12px;
365+
}
366+
367+
.v-popper__popper--no-positioning .v-popper__wrapper {
368+
width: 100%;
369+
pointer-events: auto;
370+
transition: transform .15s ease-out;
371+
}
372+
373+
.v-popper__popper--no-positioning.v-popper__popper--hidden .v-popper__wrapper {
374+
transform: translateY(100%);
375+
}
376+
</style>
377+
```

packages/docs/src/guide/css.md

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ HTML result:
116116
'v-popper__popper--hidden',
117117
'v-popper__popper--skip-transition',
118118
'v-popper__popper--arrow-overflow',
119+
'v-popper__popper--no-positioning',
119120
'v-popper__popper--show-from',
120121
'v-popper__popper--show-to',
121122
'v-popper__popper--hide-from',
@@ -149,6 +150,7 @@ The `popper` element has several dynamic classes:
149150
- `v-popper__popper--hidden`: the popper is hidden.
150151
- `v-popper__popper--skip-transition`: the transition should be skipped.
151152
- `v-popper__popper--arrow-overflow`: the arrow is overflowing past the reference, and should probably be hidden.
153+
- `v-popper__popper--no-positioning`: positioning is disabled with `positioningDisabled` prop.
152154

153155

154156
Full example style:

packages/floating-vue/src/components/Popper.ts

+29-14
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ export default () => ({
7676
default: defaultPropFactory('disabled'),
7777
},
7878

79+
positioningDisabled: {
80+
type: Boolean,
81+
default: defaultPropFactory('positioningDisabled'),
82+
},
83+
7984
placement: {
8085
type: String,
8186
default: defaultPropFactory('placement'),
@@ -269,7 +274,7 @@ export default () => ({
269274
...this.classes,
270275
popperClass: this.popperClass,
271276
},
272-
result: this.result,
277+
result: this.positioningDisabled ? null : this.result,
273278
}
274279
},
275280
},
@@ -292,12 +297,13 @@ export default () => ({
292297
}
293298
},
294299

295-
triggers () {
296-
if (!this.$_isDisposed) {
297-
this.$_removeEventListeners()
298-
this.$_addEventListeners()
299-
}
300-
},
300+
...[
301+
'triggers',
302+
'positioningDisabled',
303+
].reduce((acc, prop) => {
304+
acc[prop] = '$_refreshListeners'
305+
return acc
306+
}, {}),
301307

302308
...[
303309
'placement',
@@ -411,7 +417,7 @@ export default () => ({
411417
},
412418

413419
async $_computePosition () {
414-
if (this.$_isDisposed) return
420+
if (this.$_isDisposed || this.positioningDisabled) return
415421

416422
const options: ComputePositionConfig = {
417423
strategy: this.strategy,
@@ -764,12 +770,14 @@ export default () => ({
764770
addEvents([this.$_popperNode], HIDE_EVENT_MAP, this.popperTriggers, this.popperHideTriggers, handleHide)
765771

766772
// Scroll
767-
addListeners([
768-
...getScrollParents(this.$_referenceNode),
769-
...getScrollParents(this.$_popperNode),
770-
], 'scroll', () => {
771-
this.$_computePosition()
772-
})
773+
if (!this.positioningDisabled) {
774+
addListeners([
775+
...getScrollParents(this.$_referenceNode),
776+
...getScrollParents(this.$_popperNode),
777+
], 'scroll', () => {
778+
this.$_computePosition()
779+
})
780+
}
773781
},
774782

775783
$_removeEventListeners () {
@@ -779,6 +787,13 @@ export default () => ({
779787
this.$_events = []
780788
},
781789

790+
$_refreshListeners () {
791+
if (!this.$_isDisposed) {
792+
this.$_removeEventListeners()
793+
this.$_addEventListeners()
794+
}
795+
},
796+
782797
$_handleGlobalClose (event, touch = false) {
783798
if (this.$_showFrameLocked) return
784799

packages/floating-vue/src/components/PopperContent.vue

+11-9
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,24 @@
1414
'v-popper__popper--hide-from': classes.hideFrom,
1515
'v-popper__popper--hide-to': classes.hideTo,
1616
'v-popper__popper--skip-transition': skipTransition,
17-
'v-popper__popper--arrow-overflow': result.arrow.overflow,
17+
'v-popper__popper--arrow-overflow': result && result.arrow.overflow,
18+
'v-popper__popper--no-positioning': !result,
1819
},
1920
]"
20-
:style="{
21+
:style="result ? {
2122
position: result.strategy,
2223
transform: `translate3d(${Math.round(result.x)}px,${Math.round(result.y)}px,0)`,
23-
}"
24+
} : undefined"
2425
:aria-hidden="shown ? 'false' : 'true'"
2526
:tabindex="autoHide ? 0 : undefined"
26-
:data-popper-placement="result.placement"
27+
:data-popper-placement="result ? result.placement : undefined"
2728
@keyup.esc="autoHide && $emit('hide')"
2829
>
2930
<div
3031
class="v-popper__wrapper"
31-
:style="{
32+
:style="result ? {
3233
transformOrigin: result.transformOrigin,
33-
}"
34+
} : undefined"
3435
>
3536
<div
3637
ref="inner"
@@ -51,10 +52,10 @@
5152
<div
5253
ref="arrow"
5354
class="v-popper__arrow-container"
54-
:style="{
55+
:style="result ? {
5556
left: toPx(result.arrow.x),
5657
top: toPx(result.arrow.y),
57-
}"
58+
} : undefined"
5859
>
5960
<div class="v-popper__arrow-outer" />
6061
<div class="v-popper__arrow-inner" />
@@ -142,7 +143,8 @@ export default {
142143
height: 10px;
143144
}
144145
145-
.v-popper__popper--arrow-overflow .v-popper__arrow-container {
146+
.v-popper__popper--arrow-overflow .v-popper__arrow-container,
147+
.v-popper__popper--no-positioning .v-popper__arrow-container {
146148
display: none;
147149
}
148150

0 commit comments

Comments
 (0)