-
-
Notifications
You must be signed in to change notification settings - Fork 152
feat(BModal): use css var for zindex, add helper vars and ontop class #2556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
718c44d
5acffc6
f130e79
002742b
b372824
402c5a7
0b25eb8
23c7ad0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -15,6 +15,7 @@ | |||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||
fade: !computedNoAnimation, | ||||||||||||||||||||||||||||||||||||||
show: isVisible, | ||||||||||||||||||||||||||||||||||||||
...sharedClasses, | ||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||
]" | ||||||||||||||||||||||||||||||||||||||
role="dialog" | ||||||||||||||||||||||||||||||||||||||
|
@@ -24,7 +25,7 @@ | |||||||||||||||||||||||||||||||||||||
v-bind="$attrs" | ||||||||||||||||||||||||||||||||||||||
:style="computedZIndex" | ||||||||||||||||||||||||||||||||||||||
style="display: block" | ||||||||||||||||||||||||||||||||||||||
@mousedown.self="hide('backdrop')" | ||||||||||||||||||||||||||||||||||||||
@mousedown.left.self="hide('backdrop')" | ||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||
<div class="modal-dialog" :class="modalDialogClasses"> | ||||||||||||||||||||||||||||||||||||||
<div v-if="contentShowing" class="modal-content" :class="props.contentClass"> | ||||||||||||||||||||||||||||||||||||||
|
@@ -116,6 +117,7 @@ | |||||||||||||||||||||||||||||||||||||
:class="{ | ||||||||||||||||||||||||||||||||||||||
fade: !computedNoAnimation, | ||||||||||||||||||||||||||||||||||||||
show: backdropVisible || computedNoAnimation, | ||||||||||||||||||||||||||||||||||||||
...sharedClasses, | ||||||||||||||||||||||||||||||||||||||
}" | ||||||||||||||||||||||||||||||||||||||
@click="hide('backdrop')" | ||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||
|
@@ -127,7 +129,16 @@ | |||||||||||||||||||||||||||||||||||||
<script setup lang="ts"> | ||||||||||||||||||||||||||||||||||||||
import {onKeyStroke, unrefElement} from '@vueuse/core' | ||||||||||||||||||||||||||||||||||||||
import {useActivatedFocusTrap} from '../../composables/useActivatedFocusTrap' | ||||||||||||||||||||||||||||||||||||||
import {computed, type CSSProperties, type EmitFn, useTemplateRef, watch} from 'vue' | ||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||
computed, | ||||||||||||||||||||||||||||||||||||||
type CSSProperties, | ||||||||||||||||||||||||||||||||||||||
type EmitFn, | ||||||||||||||||||||||||||||||||||||||
nextTick, | ||||||||||||||||||||||||||||||||||||||
onMounted, | ||||||||||||||||||||||||||||||||||||||
ref, | ||||||||||||||||||||||||||||||||||||||
useTemplateRef, | ||||||||||||||||||||||||||||||||||||||
watch, | ||||||||||||||||||||||||||||||||||||||
} from 'vue' | ||||||||||||||||||||||||||||||||||||||
import type {BModalProps} from '../../types/ComponentProps' | ||||||||||||||||||||||||||||||||||||||
import type {BModalEmits} from '../../types/ComponentEmits' | ||||||||||||||||||||||||||||||||||||||
import type {BModalSlots, BModalSlotsData} from '../../types/ComponentSlots' | ||||||||||||||||||||||||||||||||||||||
|
@@ -137,7 +148,7 @@ import BCloseButton from '../BButton/BCloseButton.vue' | |||||||||||||||||||||||||||||||||||||
import {useDefaults} from '../../composables/useDefaults' | ||||||||||||||||||||||||||||||||||||||
import {useId} from '../../composables/useId' | ||||||||||||||||||||||||||||||||||||||
import {useSafeScrollLock} from '../../composables/useSafeScrollLock' | ||||||||||||||||||||||||||||||||||||||
import {isEmptySlot} from '../../utils/dom' | ||||||||||||||||||||||||||||||||||||||
import {getModalZIndex, isEmptySlot} from '../../utils/dom' | ||||||||||||||||||||||||||||||||||||||
import {useColorVariantClasses} from '../../composables/useColorVariantClasses' | ||||||||||||||||||||||||||||||||||||||
import {useModalManager} from '../../composables/useModalManager' | ||||||||||||||||||||||||||||||||||||||
import {useShowHide} from '../../composables/useShowHide' | ||||||||||||||||||||||||||||||||||||||
|
@@ -362,6 +373,7 @@ const titleClasses = computed(() => [ | |||||||||||||||||||||||||||||||||||||
['visually-hidden']: props.titleVisuallyHidden, | ||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||
]) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const disableCancel = computed(() => props.cancelDisabled || props.busy) | ||||||||||||||||||||||||||||||||||||||
const disableOk = computed(() => props.okDisabled || props.busy) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
@@ -370,12 +382,33 @@ const {activePosition, activeModalCount, stackWithoutSelf} = useModalManager( | |||||||||||||||||||||||||||||||||||||
modelValue.value | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const sharedClasses = computed(() => ({ | ||||||||||||||||||||||||||||||||||||||
[`stack-position-${activePosition?.value ?? 0}`]: true, | ||||||||||||||||||||||||||||||||||||||
[`stack-inverse-position-${(activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0)}`]: | ||||||||||||||||||||||||||||||||||||||
true, | ||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
watch(stackWithoutSelf, (newValue, oldValue) => { | ||||||||||||||||||||||||||||||||||||||
if (newValue.length > oldValue.length && showRef.value === true && props.noStacking === true) | ||||||||||||||||||||||||||||||||||||||
hide() | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const defaultModalDialogZIndex = 1056 | ||||||||||||||||||||||||||||||||||||||
const defaultModalDialogZIndex = ref(getModalZIndex(element.value ?? document.body)) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
onMounted(() => { | ||||||||||||||||||||||||||||||||||||||
watch( | ||||||||||||||||||||||||||||||||||||||
renderRef, | ||||||||||||||||||||||||||||||||||||||
(v) => { | ||||||||||||||||||||||||||||||||||||||
if (!v) return | ||||||||||||||||||||||||||||||||||||||
nextTick(() => { | ||||||||||||||||||||||||||||||||||||||
if (!element.value) return | ||||||||||||||||||||||||||||||||||||||
defaultModalDialogZIndex.value = getModalZIndex(element.value) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||
{immediate: true} | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const computedZIndexNumber = computed<number>(() => | ||||||||||||||||||||||||||||||||||||||
// Make sure that newly opened modals have a higher z-index than currently active ones. | ||||||||||||||||||||||||||||||||||||||
// All active modals have a z-index of ('defaultZIndex' - 'stackSize' - 'positionInStack'). | ||||||||||||||||||||||||||||||||||||||
|
@@ -384,15 +417,21 @@ const computedZIndexNumber = computed<number>(() => | |||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
showRef.value || isLeaving.value | ||||||||||||||||||||||||||||||||||||||
? // Just for reference there is a single frame in which the modal is not active but still has a higher z-index than the active ones due to _when_ it calculates its position. It's a small visual effect | ||||||||||||||||||||||||||||||||||||||
defaultModalDialogZIndex - | ||||||||||||||||||||||||||||||||||||||
defaultModalDialogZIndex.value - | ||||||||||||||||||||||||||||||||||||||
((activeModalCount?.value ?? 0) * 2 - (activePosition?.value ?? 0) * 2) | ||||||||||||||||||||||||||||||||||||||
: defaultModalDialogZIndex | ||||||||||||||||||||||||||||||||||||||
: defaultModalDialogZIndex.value | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
const computedZIndex = computed<CSSProperties>(() => ({ | ||||||||||||||||||||||||||||||||||||||
'z-index': computedZIndexNumber.value, | ||||||||||||||||||||||||||||||||||||||
'--b-position': activePosition?.value ?? 0, | ||||||||||||||||||||||||||||||||||||||
'--b-inverse-position': (activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0), | ||||||||||||||||||||||||||||||||||||||
'--b-count': activeModalCount?.value ?? 0, | ||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||
const computedZIndexBackdrop = computed<CSSProperties>(() => ({ | ||||||||||||||||||||||||||||||||||||||
'z-index': computedZIndexNumber.value - 1, | ||||||||||||||||||||||||||||||||||||||
'--b-position': activePosition?.value ?? 0, | ||||||||||||||||||||||||||||||||||||||
'--b-inverse-position': (activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0), | ||||||||||||||||||||||||||||||||||||||
'--b-count': activeModalCount?.value ?? 0, | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+426
to
+434
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Consider extracting CSS custom property names (e.g.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
const sharedSlots = computed<BModalSlotsData>(() => ({ | ||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -66,3 +66,11 @@ export const sortSlotElementsByPosition = ( | |||||||||||||||||
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1 | ||||||||||||||||||
return 0 | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Consider adding a JSDoc comment to explain the purpose, parameters, return value, and fallback behavior of
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||
export const getModalZIndex = (element?: Readonly<HTMLElement | null>): number => { | ||||||||||||||||||
if (typeof window === 'undefined') return 1055 | ||||||||||||||||||
const target = element ?? document.body | ||||||||||||||||||
const raw = window.getComputedStyle(target).getPropertyValue('--bs-modal-zindex').trim() | ||||||||||||||||||
const parsed = Number.parseInt(raw, 10) | ||||||||||||||||||
return Number.isFinite(parsed) ? parsed : 1055 | ||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The watcher on
renderRef
triggers a recalculation of the z-index on every render. Consider limiting the watch to CSS variable changes or debouncing to avoid unnecessarygetComputedStyle
calls.Copilot uses AI. Check for mistakes.