From 03e6aa50de21277528ca890e7f16b0cb5762c6b8 Mon Sep 17 00:00:00 2001 From: "X.Q. Chen" <31237954+brenner8023@users.noreply.github.com> Date: Wed, 27 Jul 2022 09:44:14 +0800 Subject: [PATCH] feat(cdk:utils): add zIndex manager (#1015) fix #998 --- packages/cdk/utils/__tests__/zIndex.spec.ts | 72 +++++++++++++++++++ packages/cdk/utils/index.ts | 1 + packages/cdk/utils/src/zIndex.ts | 43 +++++++++++ .../_private/overlay/src/Overlay.tsx | 15 ++-- .../components/config/src/defaultConfig.ts | 1 + packages/components/config/src/types.ts | 3 +- packages/components/drawer/src/Drawer.tsx | 9 +-- .../components/drawer/src/DrawerWrapper.tsx | 8 +-- packages/components/drawer/src/token.ts | 1 + packages/components/message/docs/Index.zh.md | 4 +- .../style/themes/default.variable.less | 2 +- packages/components/modal/src/Modal.tsx | 18 ++++- .../components/modal/src/ModalWrapper.tsx | 8 +-- packages/components/modal/src/token.ts | 1 + .../components/notification/docs/Index.zh.md | 4 +- .../style/themes/default.variable.less | 2 +- .../__snapshots__/popover.spec.ts.snap | 2 +- .../popover/__tests__/popover.spec.ts | 1 + .../components/style/variable/zindex.less | 4 +- 19 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 packages/cdk/utils/__tests__/zIndex.spec.ts create mode 100644 packages/cdk/utils/src/zIndex.ts diff --git a/packages/cdk/utils/__tests__/zIndex.spec.ts b/packages/cdk/utils/__tests__/zIndex.spec.ts new file mode 100644 index 000000000..73d3008ac --- /dev/null +++ b/packages/cdk/utils/__tests__/zIndex.spec.ts @@ -0,0 +1,72 @@ +import { mount } from '@vue/test-utils' +import { computed, defineComponent, ref, toRef } from 'vue' + +import { useZIndex } from '../src/zIndex' + +describe('zIndex.ts', () => { + const TestComp = defineComponent({ + props: { + visible: { type: Boolean, required: true }, + zIndex: { type: Number, default: undefined }, + }, + setup(props) { + const visible = toRef(props, 'visible') + const { currentZIndex } = useZIndex(toRef(props, 'zIndex'), ref(3000), visible) + const style = computed(() => ({ zIndex: currentZIndex.value })) + + return { + style, + } + }, + template: ` +
+ `, + }) + + test('custdom zIndex work', async () => { + const wrapper = mount(TestComp, { + props: { + visible: false, + zIndex: 2022, + }, + }) + + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 2022') + + await wrapper.setProps({ visible: true }) + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 2022') + }) + + test('increment zIndex work', async () => { + const wrapper = mount(TestComp, { + props: { + visible: false, + }, + }) + + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3000') + + await wrapper.setProps({ visible: true }) + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3000') + + const wrapper2 = mount(TestComp, { + props: { + visible: false, + }, + }) + await wrapper2.setProps({ visible: true }) + expect(wrapper2.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3001') + + const wrapper3 = mount(TestComp, { + props: { + visible: true, + }, + }) + expect(wrapper3.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3002') + + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3000') + await wrapper.setProps({ visible: false }) + await wrapper.setProps({ visible: true }) + expect(wrapper.find('[utid="test-el"]').attributes('style')).toContain('z-index: 3003') + }) +}) 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..2e2c12c42 --- /dev/null +++ b/packages/cdk/utils/src/zIndex.ts @@ -0,0 +1,43 @@ +/** + * @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 { type ComputedRef, type Ref, computed, ref, watch } from 'vue' + +import { isNil } from 'lodash-es' + +const zIndexCount = ref(0) + +type UseZIndex = ( + controlZIndex: Ref, + commonZIndex: Ref, + visible: Ref, +) => { + currentZIndex: ComputedRef + nextZIndex: () => number +} +export const useZIndex: UseZIndex = (controlZIndex, commonZIndex, visible) => { + const innerZIndex = ref(commonZIndex.value + zIndexCount.value) + const currentZIndex = computed(() => controlZIndex.value ?? innerZIndex.value) + const nextZIndex = () => { + if (isNil(controlZIndex.value)) { + innerZIndex.value = commonZIndex.value + zIndexCount.value + zIndexCount.value++ + } + return currentZIndex.value + } + + watch( + visible, + newVisible => { + if (newVisible) { + nextZIndex() + } + }, + { immediate: true }, + ) + return { currentZIndex, nextZIndex } +} diff --git a/packages/components/_private/overlay/src/Overlay.tsx b/packages/components/_private/overlay/src/Overlay.tsx index cfbc2e1f4..c0209733b 100644 --- a/packages/components/_private/overlay/src/Overlay.tsx +++ b/packages/components/_private/overlay/src/Overlay.tsx @@ -7,15 +7,18 @@ import type { OverlayProps } from './types' import type { PopperElement, PopperEvents } from '@idux/cdk/popper' -import type { ComputedRef, Ref, VNode } from 'vue' import { + type ComputedRef, + type Ref, Transition, + type VNode, cloneVNode, computed, defineComponent, onBeforeUnmount, onMounted, + toRef, vShow, watch, withDirectives, @@ -24,7 +27,7 @@ import { import { clickOutside } from '@idux/cdk/click-outside' import { usePopper } from '@idux/cdk/popper' import { CdkPortal } from '@idux/cdk/portal' -import { Logger, callEmit, convertElement, getFirstValidNode } from '@idux/cdk/utils' +import { Logger, callEmit, convertElement, getFirstValidNode, useZIndex } from '@idux/cdk/utils' import { useGlobalConfig } from '@idux/components/config' import { overlayProps } from './types' @@ -53,6 +56,8 @@ export default defineComponent({ destroy, } = usePopper({ ...popperOptions.value, visible: props.visible }) + const { currentZIndex } = useZIndex(toRef(props, 'zIndex'), toRef(common, 'zIndex'), visibility) + onMounted(() => initialize()) onBeforeUnmount(() => destroy()) @@ -101,6 +106,7 @@ export default defineComponent({ props, mergedPrefixCls, visibility, + currentZIndex, contentNode!, arrowRef, popperRef, @@ -133,6 +139,7 @@ function renderContent( props: OverlayProps, mergedPrefixCls: ComputedRef, visibility: ComputedRef, + currentZIndex: ComputedRef, contentNode: VNode[], arrowRef: Ref, popperRef: Ref, @@ -143,9 +150,9 @@ function renderContent( return null } const prefixCls = mergedPrefixCls.value - const { triggerId, zIndex } = props + const { triggerId } = props const overlayId = triggerId != null ? `overlay-${triggerId}` : undefined - const style = zIndex != null ? `z-index: ${zIndex}` : undefined + const style = currentZIndex.value ? `z-index: ${currentZIndex.value}` : undefined const overlay = (
{contentNode} diff --git a/packages/components/config/src/defaultConfig.ts b/packages/components/config/src/defaultConfig.ts index 399c8bcc7..866e65b7b 100644 --- a/packages/components/config/src/defaultConfig.ts +++ b/packages/components/config/src/defaultConfig.ts @@ -13,6 +13,7 @@ import { type GlobalConfig } from './types' export const defaultConfig: GlobalConfig = { common: { prefixCls: 'ix', + zIndex: 1000, }, locale: zhCN, diff --git a/packages/components/config/src/types.ts b/packages/components/config/src/types.ts index e71bf8835..a01410b3e 100644 --- a/packages/components/config/src/types.ts +++ b/packages/components/config/src/types.ts @@ -102,6 +102,7 @@ export interface GlobalConfig { export type GlobalConfigKey = keyof GlobalConfig export interface CommonConfig { prefixCls: string + zIndex: number } export interface AlertConfig { @@ -201,7 +202,6 @@ export interface DrawerConfig { maskClosable: boolean target?: PortalTargetType width: string | number - zIndex?: number } export interface DropdownConfig { @@ -301,7 +301,6 @@ export interface ModalConfig { maskClosable: boolean target?: PortalTargetType width: string | number - zIndex?: number } export interface NotificationConfig { diff --git a/packages/components/drawer/src/Drawer.tsx b/packages/components/drawer/src/Drawer.tsx index 2f9a9566b..a452656ab 100644 --- a/packages/components/drawer/src/Drawer.tsx +++ b/packages/components/drawer/src/Drawer.tsx @@ -9,11 +9,11 @@ import type { DrawerProps } from './types' import type { ScrollStrategy } from '@idux/cdk/scroll' import type { ComputedRef, Ref } from 'vue' -import { computed, defineComponent, inject, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue' +import { computed, defineComponent, inject, onBeforeUnmount, onMounted, provide, ref, toRef, watch } from 'vue' import { CdkPortal } from '@idux/cdk/portal' import { BlockScrollStrategy } from '@idux/cdk/scroll' -import { callEmit, useControlledProp } from '@idux/cdk/utils' +import { callEmit, useControlledProp, useZIndex } from '@idux/cdk/utils' import { ɵMask } from '@idux/components/_private/mask' import { useGlobalConfig } from '@idux/components/config' @@ -30,9 +30,9 @@ export default defineComponent({ const mergedPrefixCls = computed(() => `${common.prefixCls}-drawer`) const config = useGlobalConfig('drawer') const mask = computed(() => props.mask ?? config.mask) - const zIndex = computed(() => props.zIndex ?? config.zIndex) const { visible, setVisible, animatedVisible, mergedVisible } = useVisible(props) + const { currentZIndex } = useZIndex(toRef(props, 'zIndex'), toRef(common, 'zIndex'), visible) const { open, close } = useTrigger(props, setVisible) const { level, levelAction, push, pull } = useLevel(visible) @@ -46,6 +46,7 @@ export default defineComponent({ visible, animatedVisible, mergedVisible, + currentZIndex, level, levelAction, push, @@ -69,7 +70,7 @@ export default defineComponent({ class={`${mergedPrefixCls.value}-mask`} mask={mask.value} visible={visible.value} - zIndex={zIndex.value} + zIndex={currentZIndex.value} /> diff --git a/packages/components/drawer/src/DrawerWrapper.tsx b/packages/components/drawer/src/DrawerWrapper.tsx index e272170a7..f49294ac7 100644 --- a/packages/components/drawer/src/DrawerWrapper.tsx +++ b/packages/components/drawer/src/DrawerWrapper.tsx @@ -50,11 +50,12 @@ export default defineComponent({ visible, animatedVisible, mergedVisible, + currentZIndex, level, levelAction, } = inject(drawerToken)! const { close } = inject(DRAWER_TOKEN)! - const { closable, closeIcon, closeOnEsc, mask, maskClosable, zIndex } = useConfig(props, config) + const { closable, closeIcon, closeOnEsc, mask, maskClosable } = useConfig(props, config) const transitionName = computed(() => `${common.prefixCls}-${drawerTransitionMap[props.placement]}`) const isHorizontal = computed(() => horizontalPlacement.includes(props.placement)) @@ -105,7 +106,7 @@ export default defineComponent({ const wrapperStyle = computed(() => { const placement = mask.value ? undefined : placementStyle.value - return { zIndex: zIndex.value, transform: transformStyle.value, ...placement } + return { zIndex: currentZIndex.value, transform: transformStyle.value, ...placement } }) const contentStyle = computed(() => { @@ -187,9 +188,8 @@ function useConfig(props: DrawerProps, config: DrawerConfig) { const closeOnEsc = computed(() => props.closeOnEsc ?? config.closeOnEsc) const mask = computed(() => props.mask ?? config.mask) const maskClosable = computed(() => props.maskClosable ?? config.maskClosable) - const zIndex = computed(() => props.zIndex ?? config.zIndex) - return { closable, closeIcon, closeOnEsc, mask, maskClosable, zIndex } + return { closable, closeIcon, closeOnEsc, mask, maskClosable } } function watchVisibleChange( diff --git a/packages/components/drawer/src/token.ts b/packages/components/drawer/src/token.ts index 3857543ab..9fe1b732e 100644 --- a/packages/components/drawer/src/token.ts +++ b/packages/components/drawer/src/token.ts @@ -18,6 +18,7 @@ export interface DrawerContext { visible: ComputedRef animatedVisible: Ref mergedVisible: ComputedRef + currentZIndex: ComputedRef level: Ref levelAction: Ref<'push' | 'pull' | undefined> push: () => void diff --git a/packages/components/message/docs/Index.zh.md b/packages/components/message/docs/Index.zh.md index 12c726286..eef1e6ebc 100644 --- a/packages/components/message/docs/Index.zh.md +++ b/packages/components/message/docs/Index.zh.md @@ -113,10 +113,10 @@ export interface MessageRef { | `@message-icon-size` | `@font-size-lg` | - | - | | `@message-icon-margin-right` | `@spacing-sm` | - | - | | `@message-wrapper-top` | `15%` | - | - | -| `@message-wrapper-zindex` | `@zindex-l4-1` | - | - | +| `@message-wrapper-zindex` | `@zindex-l5-1` | - | - | | `@message-icon-info-color` | `@color-info-l10` | - | - | | `@message-icon-success-color` | `@color-success` | - | - | | `@message-icon-warning-color` | `@color-warning-l10` | - | - | | `@message-icon-error-color` | `@color-error-l10` | - | - | | `@message-icon-loading-color` | `@color-primary-l10` | - | - | - \ No newline at end of file + diff --git a/packages/components/message/style/themes/default.variable.less b/packages/components/message/style/themes/default.variable.less index 574763e6b..22fa79ef5 100644 --- a/packages/components/message/style/themes/default.variable.less +++ b/packages/components/message/style/themes/default.variable.less @@ -14,7 +14,7 @@ @message-icon-margin-right: @spacing-sm; @message-wrapper-top: 15%; -@message-wrapper-zindex: @zindex-l4-1; +@message-wrapper-zindex: @zindex-l5-1; @message-icon-info-color: @color-info-l10; @message-icon-success-color: @color-success; diff --git a/packages/components/modal/src/Modal.tsx b/packages/components/modal/src/Modal.tsx index 73c570eeb..d27458645 100644 --- a/packages/components/modal/src/Modal.tsx +++ b/packages/components/modal/src/Modal.tsx @@ -5,11 +5,22 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import { type ComputedRef, computed, defineComponent, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue' +import { + type ComputedRef, + computed, + defineComponent, + onBeforeUnmount, + onMounted, + provide, + ref, + toRef, + watch, +} from 'vue' import { CdkPortal } from '@idux/cdk/portal' import { BlockScrollStrategy, type ScrollStrategy } from '@idux/cdk/scroll' import { callEmit, isPromise, useControlledProp } from '@idux/cdk/utils' +import { useZIndex } from '@idux/cdk/utils/src/zIndex' import { ɵMask } from '@idux/components/_private/mask' import { useGlobalConfig } from '@idux/components/config' @@ -27,8 +38,8 @@ export default defineComponent({ const locale = useGlobalConfig('locale') const config = useGlobalConfig('modal') const mask = computed(() => props.mask ?? config.mask) - const zIndex = computed(() => props.zIndex ?? config.zIndex) const { visible, setVisible, animatedVisible, mergedVisible } = useVisible(props) + const { currentZIndex } = useZIndex(toRef(props, 'zIndex'), toRef(common, 'zIndex'), visible) const { cancelLoading, okLoading, open, close, cancel, ok } = useTrigger(props, setVisible) @@ -44,6 +55,7 @@ export default defineComponent({ mergedVisible, cancelLoading, okLoading, + currentZIndex, }) const apis = { open, close, cancel, ok } @@ -64,7 +76,7 @@ export default defineComponent({ class={`${mergedPrefixCls.value}-mask`} mask={mask.value} visible={visible.value} - zIndex={zIndex.value} + zIndex={currentZIndex.value} /> diff --git a/packages/components/modal/src/ModalWrapper.tsx b/packages/components/modal/src/ModalWrapper.tsx index 557dd1d47..7ee6eb56d 100644 --- a/packages/components/modal/src/ModalWrapper.tsx +++ b/packages/components/modal/src/ModalWrapper.tsx @@ -45,9 +45,10 @@ export default defineComponent({ mergedVisible, cancelLoading, okLoading, + currentZIndex, } = 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') @@ -77,7 +78,7 @@ export default defineComponent({ }) const wrapperStyle = computed(() => { - return { zIndex: zIndex.value } + return { zIndex: currentZIndex.value } }) const modalTransformOrigin = ref() @@ -200,9 +201,8 @@ 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 } + return { centered, closable, closeIcon, closeOnEsc, width, mask, maskClosable } } function watchVisibleChange( diff --git a/packages/components/modal/src/token.ts b/packages/components/modal/src/token.ts index 10c577705..bd41619d7 100644 --- a/packages/components/modal/src/token.ts +++ b/packages/components/modal/src/token.ts @@ -22,6 +22,7 @@ export interface ModalContext { mergedVisible: ComputedRef cancelLoading: Ref okLoading: Ref + currentZIndex: ComputedRef } export const modalToken: InjectionKey = Symbol('modalToken') diff --git a/packages/components/notification/docs/Index.zh.md b/packages/components/notification/docs/Index.zh.md index 0b4ee0e10..9d2dcd70f 100644 --- a/packages/components/notification/docs/Index.zh.md +++ b/packages/components/notification/docs/Index.zh.md @@ -139,5 +139,5 @@ export interface NotificationRef { | `@notification-content-color` | `@color-graphite-d10` | - | - | | `@notification-content-margin` | `0 16px 0 0` | - | - | | `@notification-footer-margin` | `8px 0 0 0` | - | - | -| `@notification-wrapper-zindex` | `@zindex-l4-1` | - | - | - \ No newline at end of file +| `@notification-wrapper-zindex` | `@zindex-l5-1` | - | - | + diff --git a/packages/components/notification/style/themes/default.variable.less b/packages/components/notification/style/themes/default.variable.less index 76d88b011..e578f521e 100644 --- a/packages/components/notification/style/themes/default.variable.less +++ b/packages/components/notification/style/themes/default.variable.less @@ -35,4 +35,4 @@ @notification-footer-margin: 8px 0 0 0; -@notification-wrapper-zindex: @zindex-l4-1; +@notification-wrapper-zindex: @zindex-l5-1; diff --git a/packages/components/popover/__tests__/__snapshots__/popover.spec.ts.snap b/packages/components/popover/__tests__/__snapshots__/popover.spec.ts.snap index f8d9666d9..08d352e32 100644 --- a/packages/components/popover/__tests__/__snapshots__/popover.spec.ts.snap +++ b/packages/components/popover/__tests__/__snapshots__/popover.spec.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1 -exports[`Popover > header props work 1`] = `"
TitlesubTitle
"`; +exports[`Popover > header props work 1`] = `"
TitlesubTitle
"`; exports[`Popover > render work 1`] = ` "
trigger
diff --git a/packages/components/popover/__tests__/popover.spec.ts b/packages/components/popover/__tests__/popover.spec.ts index 64132562c..afe32b7f5 100644 --- a/packages/components/popover/__tests__/popover.spec.ts +++ b/packages/components/popover/__tests__/popover.spec.ts @@ -37,6 +37,7 @@ describe('Popover', () => { test('header props work', async () => { PopoverWrapper({ props: { + zIndex: 2022, visible: true, header: { title: 'Title', diff --git a/packages/components/style/variable/zindex.less b/packages/components/style/variable/zindex.less index 3545b72cc..1f2b6eb3c 100644 --- a/packages/components/style/variable/zindex.less +++ b/packages/components/style/variable/zindex.less @@ -5,10 +5,10 @@ @zindex-l2-base: 10; // affix back-top spin panel dots @zindex-l3-base: 100; @zindex-l4-base: 1000; // drawer modal -@zindex-l4-1: 1010; // message notification +@zindex-l4-1: 1010; @zindex-l4-2: 1020; // popover @zindex-l4-3: 1030; // overlay cascader date-picker dropdown @zindex-l4-4: 1040; // popoconfirm @zindex-l4-5: 1050; // tooltip @zindex-l4-6: 1060; // image -@zindex-l5-1: 10010; // loading-bar +@zindex-l5-1: 10010; // loading-bar message notification