Skip to content

Commit 975121d

Browse files
authored
feat(useZIndex): new composable (#156)
this composable allows handling z-index dynamically avoiding issues where floating elements open behind another floating element
1 parent 7ae732f commit 975121d

File tree

3 files changed

+100
-4
lines changed

3 files changed

+100
-4
lines changed

packages/anu-vue/src/components/floating/AFloating.vue

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<script lang="ts" setup>
22
import { autoUpdate, useFloating } from '@floating-ui/vue'
33
import { onClickOutside, useEventListener, useMounted } from '@vueuse/core'
4+
import type { CSSProperties } from 'vue'
45
import { ref } from 'vue'
56
import type { AFloatingEvents, aFloatingSlots } from './meta'
67
import { aFloatingProps } from './meta'
78
import { useTeleport } from '@/composables/useTeleport'
9+
import { useZIndex } from '@/composables/useZIndex'
810
911
const props = defineProps(aFloatingProps)
1012
const emit = defineEmits<AFloatingEvents>()
@@ -47,6 +49,17 @@ const { x, y, strategy } = useFloating(toRef(props, 'referenceEl'), refFloating,
4749
whileElementsMounted: autoUpdate,
4850
})
4951
52+
const { nextZIndex } = useZIndex()
53+
const zIndex = nextZIndex()
54+
55+
const contentStyle = computed<CSSProperties>(() => {
56+
return {
57+
top: `${unref(y) ?? 0}px`,
58+
left: `${unref(x) ?? 0}px`,
59+
zIndex,
60+
}
61+
})
62+
5063
// onMounted(() => {
5164
// const vm = getCurrentInstance()
5265
// console.log('vm?.proxy?.$el :>> ', vm?.proxy?.$parent)
@@ -119,10 +132,7 @@ defineExpose({
119132
v-bind="$attrs"
120133
ref="refFloating"
121134
class="a-floating transform"
122-
:style="{
123-
top: `${y ?? 0}px`,
124-
left: `${x ?? 0}px`,
125-
}"
135+
:style="contentStyle"
126136
:class="strategy"
127137
>
128138
<slot />
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { InjectionKey, Ref } from 'vue'
2+
import { computed, inject, ref, unref } from 'vue'
3+
import { isNumber } from '@vueuse/core'
4+
5+
// TODO add Config Provider Component
6+
export const zIndexContextKey: InjectionKey<Ref<number | undefined>> = Symbol('zIndexContextKey')
7+
8+
const zIndexCounter = ref(0)
9+
export const defaultBaseZIndex = 2000 as const
10+
11+
export function useZIndex() {
12+
const injectedZIndex = inject(zIndexContextKey)
13+
14+
const baseZIndex = computed(() => {
15+
const injectedZIndexValue = unref(injectedZIndex)
16+
17+
return isNumber(injectedZIndexValue)
18+
? injectedZIndexValue
19+
: defaultBaseZIndex
20+
})
21+
22+
const activeZIndex = computed(() => baseZIndex.value + zIndexCounter.value)
23+
24+
const nextZIndex = () => {
25+
zIndexCounter.value++
26+
27+
return activeZIndex.value
28+
}
29+
30+
return {
31+
baseZIndex,
32+
activeZIndex,
33+
nextZIndex,
34+
}
35+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { describe, expect, it } from 'vitest'
2+
import type { ComponentPublicInstance } from 'vue'
3+
import { defineComponent, nextTick, ref } from 'vue'
4+
import type { VueWrapper } from '@vue/test-utils'
5+
import { mount } from '@vue/test-utils'
6+
import { defaultBaseZIndex, useZIndex, zIndexContextKey } from '../../src/composables/useZIndex'
7+
8+
describe('useZIndex', () => {
9+
let wrapper: VueWrapper<ComponentPublicInstance>
10+
11+
const mountComponent = (provideZIndex?: number) => mount(
12+
defineComponent({
13+
setup(_, { expose }) {
14+
const zIndex = useZIndex()
15+
expose(zIndex)
16+
},
17+
template: '<div></div>',
18+
}),
19+
{
20+
global: {
21+
provide: {
22+
[zIndexContextKey]: ref(provideZIndex),
23+
},
24+
},
25+
},
26+
)
27+
28+
it('should have the default baseZIndex when no custom zIndex is provided', async () => {
29+
wrapper = mountComponent()
30+
await nextTick()
31+
expect(wrapper.vm.baseZIndex).toBe(defaultBaseZIndex)
32+
})
33+
34+
it('should use the provided custom zIndex', async () => {
35+
const zIndex = 1000
36+
wrapper = mountComponent(zIndex)
37+
const { vm } = wrapper
38+
await nextTick()
39+
expect(vm.baseZIndex).toBe(zIndex)
40+
})
41+
42+
it('should increment zIndex correctly', async () => {
43+
wrapper = mountComponent()
44+
const { vm } = wrapper
45+
await nextTick()
46+
const initialZIndex = vm.activeZIndex
47+
const incrementedZIndex = vm.nextZIndex()
48+
expect(incrementedZIndex).toBe(initialZIndex + 1)
49+
expect(vm.activeZIndex).toBe(initialZIndex + 1)
50+
})
51+
})

0 commit comments

Comments
 (0)