From b362a75a68c33aa6726b4dbaa438624890df4da4 Mon Sep 17 00:00:00 2001 From: "X.Q. Chen" <31237954+brenner8023@users.noreply.github.com> Date: Thu, 14 Jul 2022 00:54:15 +0800 Subject: [PATCH] feat(cdk:*): add zIndexManager --- packages/cdk/utils/index.ts | 1 + packages/cdk/utils/src/zIndex.ts | 73 +++++++++++++++++++ .../components/modal/__tests__/modal.spec.ts | 9 ++- .../components/modal/src/ModalWrapper.tsx | 22 +++--- 4 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 packages/cdk/utils/src/zIndex.ts diff --git a/packages/cdk/utils/index.ts b/packages/cdk/utils/index.ts index 4b31faa51..1e02b401b 100644 --- a/packages/cdk/utils/index.ts +++ b/packages/cdk/utils/index.ts @@ -17,3 +17,4 @@ export * from './src/typeof' export * from './src/uniqueId' export * from './src/useEventListener' export * from './src/vNode' +export * from './src/zIndex' diff --git a/packages/cdk/utils/src/zIndex.ts b/packages/cdk/utils/src/zIndex.ts new file mode 100644 index 000000000..22c1ec048 --- /dev/null +++ b/packages/cdk/utils/src/zIndex.ts @@ -0,0 +1,73 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +import { Logger } from '@idux/cdk/utils' + +class ZIndexManager { + private zIndexMap: Map = new Map() + protected initZIndex = 10000 + protected nextZIndex: number + + constructor() { + this.nextZIndex = this.initZIndex + } + + private get elementCount() { + return this.zIndexMap.size + } + + public register(el: HTMLElement, zIndex?: number) { + const { zIndexMap } = this + if (typeof zIndex !== 'undefined') { + el.style.zIndex = `${zIndex}` + zIndexMap.delete(el) + return + } + const { nextZIndex } = this + if (zIndexMap.has(el)) { + const currentZIndex = zIndexMap.get(el)! + if (currentZIndex + 1 === this.nextZIndex) { + return + } + } + el.style.zIndex = `${nextZIndex}` + zIndexMap.set(el, nextZIndex) + this.nextZIndex = nextZIndex + 1 + } + + public unregister(el: HTMLElement) { + const { zIndexMap } = this + if (zIndexMap.has(el)) { + zIndexMap.delete(el) + } else if (__DEV__) { + Logger.warn('cdk/zIndex', `Element not found when unregister`) + } + if (this.canResetState()) { + this.resetState() + } + } + + private canResetState() { + return this.elementCount === 0 + } + + private resetState() { + this.nextZIndex = this.initZIndex + } +} + +const modalInitZIndex = 1000 + +class ModalZIndexManager extends ZIndexManager { + protected initZIndex: number = modalInitZIndex + + public setInitZIndex(newZIndex: number) { + this.initZIndex = newZIndex + } +} + +export const modalZIndexManager = new ModalZIndexManager() diff --git a/packages/components/modal/__tests__/modal.spec.ts b/packages/components/modal/__tests__/modal.spec.ts index 2d313c49c..d0744dbbd 100644 --- a/packages/components/modal/__tests__/modal.spec.ts +++ b/packages/components/modal/__tests__/modal.spec.ts @@ -391,12 +391,13 @@ describe('Modal', () => { }) test('zIndex work', async () => { - const wrapper = ModalMount({ props: { zIndex: 1001 } }) - expect(document.querySelector('.ix-modal-wrapper')!.getAttribute('style')).toContain('z-index: 1001') + const wrapper = ModalMount({ props: { zIndex: 2001 } }) + expect(document.querySelector('.ix-modal-wrapper')!.getAttribute('style')).toContain('z-index: 2001') - await wrapper.setProps({ zIndex: 1002 }) + await wrapper.setProps({ visible: false }) + await wrapper.setProps({ visible: true }) - expect(document.querySelector('.ix-modal-wrapper')!.getAttribute('style')).toContain('z-index: 1002') + expect(document.querySelector('.ix-modal-wrapper')!.getAttribute('style')).toContain('z-index: 2001') }) describe('Events', () => { diff --git a/packages/components/modal/src/ModalWrapper.tsx b/packages/components/modal/src/ModalWrapper.tsx index 1b5d5c593..f6daf1a10 100644 --- a/packages/components/modal/src/ModalWrapper.tsx +++ b/packages/components/modal/src/ModalWrapper.tsx @@ -21,7 +21,7 @@ import { import { isFunction } from 'lodash-es' import { useDraggable } from '@idux/cdk/drag-drop' -import { callEmit, convertCssPixel, getOffset } from '@idux/cdk/utils' +import { callEmit, convertCssPixel, getOffset, modalZIndexManager } from '@idux/cdk/utils' import { ɵFooter } from '@idux/components/_private/footer' import { ɵHeader } from '@idux/components/_private/header' import { type ModalConfig } from '@idux/components/config' @@ -47,7 +47,7 @@ export default defineComponent({ okLoading, } = inject(modalToken)! const { close, cancel, ok } = inject(MODAL_TOKEN)! - const { centered, closable, closeIcon, closeOnEsc, width, mask, maskClosable, zIndex } = useConfig(props, config) + const { centered, closable, closeIcon, closeOnEsc, width, mask, maskClosable } = useConfig(props, config) const cancelVisible = computed(() => props.type === 'default' || props.type === 'confirm') @@ -76,10 +76,6 @@ export default defineComponent({ } }) - const wrapperStyle = computed(() => { - return { zIndex: zIndex.value } - }) - const modalTransformOrigin = ref() const contentStyle = computed(() => { return { transformOrigin: modalTransformOrigin.value, ...placementStyle.value } @@ -135,7 +131,6 @@ export default defineComponent({ v-show={mergedVisible.value} ref={wrapperRef} class={wrapperClasses.value} - style={wrapperStyle.value} tabindex={-1} onClick={onWrapperClick} onKeydown={onWrapperKeydown} @@ -200,9 +195,12 @@ function useConfig(props: ModalProps, config: ModalConfig) { const mask = computed(() => props.mask ?? config.mask) const maskClosable = computed(() => props.maskClosable ?? config.maskClosable) const width = computed(() => convertCssPixel(props.width ?? config.width)) - const zIndex = computed(() => props.zIndex ?? config.zIndex) - return { centered, closable, closeIcon, closeOnEsc, width, mask, maskClosable, zIndex } + if (config.zIndex) { + modalZIndexManager.setInitZIndex(config.zIndex) + } + + return { centered, closable, closeIcon, closeOnEsc, width, mask, maskClosable } } function watchVisibleChange( @@ -217,15 +215,19 @@ function watchVisibleChange( watch( () => props.visible, visible => { + const wrapperElement = wrapperRef.value! if (visible) { - const wrapperElement = wrapperRef.value! const activeElement = document.activeElement if (!wrapperElement.contains(activeElement)) { lastOutSideActiveElement = activeElement as HTMLElement sentinelStartRef.value?.focus() } draggableResult.value?.reset() + + modalZIndexManager.register(wrapperElement, props.zIndex) } else { + modalZIndexManager.unregister(wrapperElement) + if (mask.value) { lastOutSideActiveElement?.focus?.() lastOutSideActiveElement = null