Skip to content

Commit bce8477

Browse files
authored
feat: add positioning options to FwbModal (#293)
* fix: correct close button alignment in rtl mode * feat: add positioning options to FwbModal * docs: add position example for FwbModal * fix: change position types to logical ones * fix: annotate objects
1 parent 0cc202f commit bce8477

File tree

5 files changed

+115
-8
lines changed

5 files changed

+115
-8
lines changed

docs/components/modal.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import FwbModalExample from './modal/examples/FwbModalExample.vue'
33
import FwbModalExampleSize from './modal/examples/FwbModalExampleSize.vue'
44
import FwbModalExampleEscapable from './modal/examples/FwbModalExampleEscapable.vue'
55
import FwbModalExamplePersistent from './modal/examples/FwbModalExamplePersistent.vue'
6+
import FwbModalExamplePosition from './modal/examples/FwbModalExamplePosition.vue'
67
</script>
78
# Vue Modal - Flowbite
89

@@ -91,6 +92,33 @@ import { FwbModal } from 'flowbite-vue'
9192
</script>
9293
```
9394

95+
## Position
96+
97+
The `position` prop allows you to control the placement of the modal on the screen, taking into account RTL (Right-to-Left) mode. You can choose from the following options:
98+
99+
`top-start`, `top-center`, `top-end`, `center-start`, `center`, `center-end`, `bottom-start`, `bottom-center`, `bottom-end`
100+
101+
The default value is: `center`
102+
103+
<fwb-modal-example-position />
104+
```vue
105+
<template>
106+
<fwb-modal position="top-start" />
107+
<fwb-modal position="top-center" />
108+
<fwb-modal position="top-end" />
109+
<fwb-modal position="center-start" />
110+
<fwb-modal position="center" />
111+
<fwb-modal position="center-end" />
112+
<fwb-modal position="bottom-start" />
113+
<fwb-modal position="bottom-center" />
114+
<fwb-modal position="bottom-end" />
115+
</template>
116+
117+
<script setup>
118+
import { FwbModal } from 'flowbite-vue'
119+
</script>
120+
```
121+
94122
## Escapable
95123

96124
The escapable property is true by default to improve user experience and accessibility.

docs/components/modal/examples/FwbModalExample.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:not-escapable="notEscapable"
99
:persistent="persistent"
1010
:size="size"
11+
:position="position"
1112
@close="closeModal"
1213
>
1314
<template #header>
@@ -45,20 +46,22 @@
4546
<script lang="ts" setup>
4647
import { ref } from 'vue'
4748
import { FwbButton, FwbModal } from '../../../../src/index'
48-
import { type ModalSize } from '../../../../src/components/FwbModal/types'
49+
import { type ModalPosition, type ModalSize } from '../../../../src/components/FwbModal/types'
4950
5051
interface ModalProps {
5152
size?: ModalSize,
5253
notEscapable?: boolean,
5354
persistent?: boolean,
5455
triggerText?: string
56+
position?: ModalPosition
5557
}
5658
5759
withDefaults(defineProps<ModalProps>(), {
5860
size: '2xl',
5961
notEscapable: false,
6062
persistent: false,
6163
triggerText: 'Open Modal',
64+
position: 'center',
6265
})
6366
6467
const isShowModal = ref(false)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<template>
2+
<div class="flex flex-wrap justify-start gap-2 vp-raw">
3+
<span>
4+
<fwb-modal-example
5+
position="top-start"
6+
trigger-text="Top Start"
7+
/>
8+
</span>
9+
<span>
10+
<fwb-modal-example
11+
position="top-center"
12+
trigger-text="Top Center"
13+
/>
14+
</span>
15+
<span>
16+
<fwb-modal-example
17+
position="top-end"
18+
trigger-text="Top End"
19+
/>
20+
</span>
21+
<span>
22+
<fwb-modal-example
23+
position="center-start"
24+
trigger-text="Center Start"
25+
/>
26+
</span>
27+
<span>
28+
<fwb-modal-example
29+
position="center"
30+
trigger-text="Center"
31+
/>
32+
</span>
33+
<span>
34+
<fwb-modal-example
35+
position="center-end"
36+
trigger-text="Center End"
37+
/>
38+
</span>
39+
<span>
40+
<fwb-modal-example
41+
position="bottom-start"
42+
trigger-text="Bottom Start"
43+
/>
44+
</span>
45+
<span>
46+
<fwb-modal-example
47+
position="bottom-center"
48+
trigger-text="Bottom Center"
49+
/>
50+
</span>
51+
<span>
52+
<fwb-modal-example
53+
position="bottom-end"
54+
trigger-text="Bottom End"
55+
/>
56+
</span>
57+
</div>
58+
</template>
59+
60+
<script setup>
61+
import FwbModalExample from './FwbModalExample.vue'
62+
</script>

src/components/FwbModal/FwbModal.vue

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
<div class="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40" />
44
<div
55
ref="modalRef"
6-
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 w-full md:inset-0 h-modal md:h-full justify-center items-center flex"
6+
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 w-full md:inset-0 h-modal md:h-full grid"
77
tabindex="0"
88
@click.self="clickOutside"
99
@keyup.esc="closeWithEsc"
1010
>
1111
<div
12-
:class="`${modalSizeClasses[size]}`"
13-
class="relative p-4 w-full h-full"
12+
:class="`${modalSizeClasses[size]} ${modalPositionClasses[position]}`"
13+
class="relative p-4 w-full"
1414
>
1515
<!-- Modal content -->
1616
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
@@ -23,7 +23,7 @@
2323
<button
2424
v-if="!persistent"
2525
aria-label="close"
26-
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"
26+
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ms-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"
2727
type="button"
2828
@click="closeModal"
2929
>
@@ -63,22 +63,24 @@
6363

6464
<script lang="ts" setup>
6565
import { onMounted, ref, type Ref } from 'vue'
66-
import type { ModalSize } from './types'
66+
import type { ModalPosition, ModalSize } from './types'
6767
6868
interface ModalProps {
6969
notEscapable?: boolean,
7070
persistent?: boolean
7171
size?: ModalSize,
72+
position?: ModalPosition
7273
}
7374
7475
const props = withDefaults(defineProps<ModalProps>(), {
7576
notEscapable: false,
7677
persistent: false,
7778
size: '2xl',
79+
position: 'center',
7880
})
7981
8082
const emit = defineEmits(['close', 'click:outside'])
81-
const modalSizeClasses = {
83+
const modalSizeClasses: Record<ModalSize, string> = {
8284
xs: 'max-w-xs',
8385
sm: 'max-w-sm',
8486
md: 'max-w-md',
@@ -92,6 +94,18 @@ const modalSizeClasses = {
9294
'7xl': 'max-w-7xl',
9395
}
9496
97+
const modalPositionClasses: Record<ModalPosition, string> = {
98+
'top-start': 'self-start justify-self-start',
99+
'top-center': 'self-start justify-self-center',
100+
'top-end': 'self-start justify-self-end',
101+
'center-start': 'self-center justify-self-start',
102+
center: 'self-center justify-self-center',
103+
'center-end': 'self-center justify-self-end',
104+
'bottom-start': 'self-end justify-self-start',
105+
'bottom-center': 'self-end justify-self-center',
106+
'bottom-end': 'self-end justify-self-end',
107+
}
108+
95109
function closeModal () {
96110
emit('close')
97111
}

src/components/FwbModal/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export type ModalPosition = 'bottom-left' | 'bottom-right' | 'bottom-center' | 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right';
1+
export type ModalPosition = 'bottom-start' | 'bottom-end' | 'bottom-center' | 'top-start' | 'top-center' | 'top-end' | 'center-start' | 'center' | 'center-end';
22
export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl';

0 commit comments

Comments
 (0)