Skip to content
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

feat(comp:drawer): distance is configurable and determined by drawer … #1767

Merged
merged 1 commit into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components/config/src/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const defaultConfig: GlobalConfig = {
closable: true,
closeOnEsc: true,
closeIcon: 'close-filled',
distance: 160,
height: 256,
mask: true,
maskClosable: true,
Expand Down
1 change: 1 addition & 0 deletions packages/components/config/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ export interface DrawerConfig {
closeIcon: string
closeOnEsc: boolean
container?: PortalTargetType
distance: number
height: string | number
mask: boolean
maskClosable: boolean
Expand Down
2 changes: 1 addition & 1 deletion packages/components/drawer/demo/MultiLevel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<IxDrawer v-model:visible="visible" header="Parent drawer">
<p>This is parent drawer</p>
<IxButton @click="showChildDrawer">Open Child Drawer</IxButton>
<IxDrawer v-model:visible="childVisible" header="Child drawer">
<IxDrawer v-model:visible="childVisible" :width="800" header="Child drawer">
<p>This is child drawer</p>
<IxButton @click="showGrandchildDrawer">Open Grandchild Drawer</IxButton>
<IxDrawer v-model:visible="grandchildVisible" header="Grandchild drawer">
Expand Down
1 change: 1 addition & 0 deletions packages/components/drawer/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
| `maskClosable` | 点击蒙层是否允许关闭 | `boolean` | `true` | ✅ | - |
| `offset` | 抽屉偏移量 | `number \| string` | `0` | - | `placement` 为`start/end` 时, 为顶部偏移量,`top/bottom` 时, 为左边偏移量 |
| `placement` | 抽屉打开方向 | `'top' \| 'bottom' \| 'start' \| 'end'` | `'end'` | - | - |
| `distance` | 多层抽屉场景与子抽屉的距离 | `number` | `160` | ✅ | 如果大于抽屉的宽度,则以抽屉的宽度为距离 |
| `width` | 抽屉宽度 | `string \| number` | `'480'` | ✅ | 默认值仅在 `placement为` 为 `start/end` 时生效,其他情况默认为 `100%` |
| `zIndex` | 设置抽屉的 `z-index` | `number` | - | - | - |
| `onAfterOpen` | 打开后的回调 | `() => void` | - | - | - |
Expand Down
80 changes: 68 additions & 12 deletions packages/components/drawer/src/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from 'vue'

import { CdkPortal } from '@idux/cdk/portal'
import { useResizeObserver } from '@idux/cdk/resize'
import { BlockScrollStrategy, type ScrollStrategy } from '@idux/cdk/scroll'
import { callEmit, useControlledProp } from '@idux/cdk/utils'
import { ɵMask } from '@idux/components/_private/mask'
Expand All @@ -48,26 +49,30 @@ export default defineComponent({
const mergedPortalTarget = usePortalTarget(props, config, common, mergedPrefixCls)

const mask = computed(() => props.mask ?? config.mask)
const mergedDistance = computed(() => props.distance ?? config.distance)

const { loaded, delayedLoaded, visible, setVisible, animatedVisible, mergedVisible } = useVisible(props)
const currentZIndex = useZIndex(toRef(props, 'zIndex'), toRef(common, 'overlayZIndex'), visible)

const drawerElRef = ref<HTMLElement>()

const { open, close } = useTrigger(props, setVisible)
const { level, levelAction, push, pull } = useLevel(visible)
const { levelAction, distance, push, pull } = useLevel(props, visible, mergedDistance, drawerElRef)

provide(drawerToken, {
props,
slots,
common,
config,
mergedPrefixCls,
drawerElRef,
visible,
delayedLoaded,
animatedVisible,
mergedVisible,
currentZIndex,
level,
levelAction,
distance,
push,
pull,
})
Expand Down Expand Up @@ -181,27 +186,78 @@ function useTrigger(props: DrawerProps, setVisible: (visible: boolean) => void)
return { open, close }
}

function useLevel(visible: Ref<boolean>) {
function useLevel(
props: DrawerProps,
visible: Ref<boolean>,
mergedDistance: ComputedRef<number>,
drawerElRef: Ref<HTMLElement | undefined>,
) {
const parentContext = inject(drawerToken, null)

const level = ref(0)
const distance = ref(0)
const levelAction = ref<'push' | 'pull'>()
const drawerSize = ref(0)
const sizeAttrName = computed(() => (['top', 'bottom'].includes(props.placement) ? 'height' : 'width'))

let sizeUpdateCb: (() => void) | undefined

useResizeObserver(drawerElRef, ({ contentRect }) => {
drawerSize.value = contentRect[sizeAttrName.value] ?? 0

sizeUpdateCb?.()
})

const onSizeUpdate = (cb: () => void) => {
sizeUpdateCb = () => {
cb()
sizeUpdateCb = undefined
}
}

const updateDistance = (childSize: number) => {
const minDisatance = Math.min(drawerSize.value, mergedDistance.value)
if (!drawerSize.value || !childSize || drawerSize.value - childSize >= minDisatance) {
distance.value = 0
} else {
distance.value = minDisatance - (drawerSize.value - childSize)
}
}

const push = () => {
const push = (childSize: number) => {
level.value++
parentContext?.push()

updateDistance(childSize)
pushParent()
}

const pull = () => {
const pull = (childSize: number) => {
level.value--
parentContext?.pull()

updateDistance(childSize)
pullParent()
}

const pushParent = () => {
if (parentContext?.props.placement !== props.placement) {
return
}

parentContext?.push(drawerSize.value + distance.value)
}
const pullParent = () => {
if (parentContext?.props.placement !== props.placement) {
return
}

parentContext?.pull(visible.value ? drawerSize.value + distance.value : 0)
}

watch(visible, value => {
if (value) {
parentContext?.push()
onSizeUpdate(pushParent)
} else {
parentContext?.pull()
pullParent()
levelAction.value = undefined
}
})
Expand All @@ -212,15 +268,15 @@ function useLevel(visible: Ref<boolean>) {

onMounted(() => {
if (visible.value) {
parentContext?.push()
pushParent()
}
})

onBeforeUnmount(() => {
if (visible.value) {
parentContext?.pull()
pullParent()
}
})

return { level, levelAction, push, pull }
return { levelAction, distance, push, pull }
}
12 changes: 7 additions & 5 deletions packages/components/drawer/src/DrawerWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const drawerTransitionMap = {
end: 'move-end',
}
const horizontalPlacement = ['start', 'end']
const defaultDistance = 160

export default defineComponent({
inheritAttrs: false,
Expand All @@ -49,13 +48,14 @@ export default defineComponent({
common,
config,
mergedPrefixCls,
drawerElRef,
visible,
delayedLoaded,
animatedVisible,
mergedVisible,
currentZIndex,
level,
levelAction,
distance,
} = inject(drawerToken)!
const { close } = inject(DRAWER_TOKEN)!
const { closable, closeIcon, closeOnEsc, mask, maskClosable } = useConfig(props, config)
Expand Down Expand Up @@ -83,12 +83,13 @@ export default defineComponent({
const transformStyle = computed(() => {
const { placement } = props
const horizontal = isHorizontal.value
const distance = level.value * defaultDistance
let transform
if (horizontal) {
transform = distance > 0 ? `translateX(${placement === 'start' ? distance : -distance}px)` : undefined
transform =
distance.value > 0 ? `translateX(${placement === 'start' ? distance.value : -distance.value}px)` : undefined
} else {
transform = distance > 0 ? `translateY(${placement === 'top' ? distance : -distance}px)` : undefined
transform =
distance.value > 0 ? `translateY(${placement === 'top' ? distance.value : -distance.value}px)` : undefined
}
return transform
})
Expand Down Expand Up @@ -158,6 +159,7 @@ export default defineComponent({
{delayedLoaded.value && (
<div
v-show={visible.value}
ref={drawerElRef}
role="document"
class={prefixCls}
style={contentStyle.value}
Expand Down
7 changes: 4 additions & 3 deletions packages/components/drawer/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ export interface DrawerContext {
common: CommonConfig
config: DrawerConfig
mergedPrefixCls: ComputedRef<string>
drawerElRef: Ref<HTMLElement | undefined>
visible: Ref<boolean>
delayedLoaded: Ref<boolean>
animatedVisible: Ref<boolean | undefined>
mergedVisible: ComputedRef<boolean>
currentZIndex: ComputedRef<number>
level: Ref<number>
levelAction: Ref<'push' | 'pull' | undefined>
push: () => void
pull: () => void
distance: Ref<number>
push: (childSize: number) => void
pull: (childSize: number) => void
}

export const drawerToken: InjectionKey<DrawerContext> = Symbol('drawerToken')
Expand Down
4 changes: 4 additions & 0 deletions packages/components/drawer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ export const drawerProps = {
type: String as PropType<DrawerPlacement>,
default: 'end',
},
distance: {
type: Number,
default: undefined,
},
scrollStrategy: Object as PropType<ScrollStrategy>,
width: [String, Number] as PropType<string | number>,
zIndex: Number,
Expand Down