refactor: drawer
parent
c7b15a96a8
commit
8fcb3fdfe3
|
@ -27,7 +27,7 @@ export const getTransitionProps = (transitionName: string, opt: TransitionProps
|
|||
// appearFromClass: `${transitionName}-appear ${transitionName}-appear-prepare`,
|
||||
// appearActiveClass: `antdv-base-transtion`,
|
||||
// appearToClass: `${transitionName}-appear ${transitionName}-appear-active`,
|
||||
enterFromClass: `${transitionName}-enter ${transitionName}-enter-prepare`,
|
||||
enterFromClass: `${transitionName}-enter ${transitionName}-enter-prepare ${transitionName}-enter-start`,
|
||||
enterActiveClass: `${transitionName}-enter ${transitionName}-enter-prepare`,
|
||||
enterToClass: `${transitionName}-enter ${transitionName}-enter-active`,
|
||||
leaveFromClass: ` ${transitionName}-leave`,
|
||||
|
|
|
@ -19,12 +19,14 @@ Basic drawer.
|
|||
<template>
|
||||
<a-button type="primary" @click="showDrawer">Open</a-button>
|
||||
<a-drawer
|
||||
v-model:visible="visible"
|
||||
v-model:open="open"
|
||||
class="custom-class"
|
||||
root-class-name="root-class-name"
|
||||
:root-style="{ color: 'blue' }"
|
||||
style="color: red"
|
||||
title="Basic Drawer"
|
||||
placement="right"
|
||||
@after-visible-change="afterVisibleChange"
|
||||
@after-open-change="afterOpenChange"
|
||||
>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
|
@ -35,19 +37,19 @@ Basic drawer.
|
|||
import { defineComponent, ref } from 'vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const afterVisibleChange = (bool: boolean) => {
|
||||
console.log('visible', bool);
|
||||
const afterOpenChange = (bool: boolean) => {
|
||||
console.log('open', bool);
|
||||
};
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
return {
|
||||
visible,
|
||||
afterVisibleChange,
|
||||
open,
|
||||
afterOpenChange,
|
||||
showDrawer,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -24,13 +24,7 @@ Extra actions should be placed at corner of drawer in Ant Design, you can using
|
|||
<a-radio value="left">left</a-radio>
|
||||
</a-radio-group>
|
||||
<a-button type="primary" @click="showDrawer">Open</a-button>
|
||||
<a-drawer
|
||||
:width="500"
|
||||
title="Basic Drawer"
|
||||
:placement="placement"
|
||||
:visible="visible"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-drawer :width="500" title="Basic Drawer" :placement="placement" :open="open" @close="onClose">
|
||||
<template #extra>
|
||||
<a-button style="margin-right: 8px" @click="onClose">Cancel</a-button>
|
||||
<a-button type="primary" @click="onClose">Submit</a-button>
|
||||
|
@ -46,18 +40,18 @@ import type { DrawerProps } from 'ant-design-vue';
|
|||
export default defineComponent({
|
||||
setup() {
|
||||
const placement = ref<DrawerProps['placement']>('left');
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
return {
|
||||
placement,
|
||||
visible,
|
||||
open,
|
||||
showDrawer,
|
||||
onClose,
|
||||
};
|
||||
|
|
|
@ -24,7 +24,7 @@ Use form in drawer with submit button.
|
|||
<a-drawer
|
||||
title="Create a new account"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:open="open"
|
||||
:body-style="{ paddingBottom: '80px' }"
|
||||
:footer-style="{ textAlign: 'right' }"
|
||||
@close="onClose"
|
||||
|
@ -134,19 +134,19 @@ export default defineComponent({
|
|||
description: [{ required: true, message: 'Please enter url description' }],
|
||||
};
|
||||
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
return {
|
||||
form,
|
||||
rules,
|
||||
visible,
|
||||
open,
|
||||
showDrawer,
|
||||
onClose,
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ Open a new drawer on top of an existing drawer to handle multi branch tasks.
|
|||
<template>
|
||||
<a-button type="primary" @click="showDrawer">Open</a-button>
|
||||
<a-drawer
|
||||
v-model:visible="visible"
|
||||
v-model:open="open"
|
||||
title="Multi-level drawer"
|
||||
width="520"
|
||||
:closable="false"
|
||||
|
@ -27,12 +27,7 @@ Open a new drawer on top of an existing drawer to handle multi branch tasks.
|
|||
@close="onClose"
|
||||
>
|
||||
<a-button type="primary" @click="showChildrenDrawer">Two-level drawer</a-button>
|
||||
<a-drawer
|
||||
v-model:visible="childrenDrawer"
|
||||
title="Two-level Drawer"
|
||||
width="320"
|
||||
:closable="false"
|
||||
>
|
||||
<a-drawer v-model:open="childrenDrawer" title="Two-level Drawer" width="320" :closable="false">
|
||||
<a-button type="primary" @click="showChildrenDrawer">This is two-level drawer</a-button>
|
||||
</a-drawer>
|
||||
|
||||
|
@ -47,21 +42,21 @@ import { defineComponent, ref } from 'vue';
|
|||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const childrenDrawer = ref<boolean>(false);
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
const showChildrenDrawer = () => {
|
||||
childrenDrawer.value = true;
|
||||
};
|
||||
return {
|
||||
visible,
|
||||
open,
|
||||
childrenDrawer,
|
||||
showDrawer,
|
||||
onClose,
|
||||
|
|
|
@ -28,7 +28,7 @@ The Drawer can appear from any edge of the screen.
|
|||
title="Basic Drawer"
|
||||
:placement="placement"
|
||||
:closable="false"
|
||||
:visible="visible"
|
||||
:open="open"
|
||||
@close="onClose"
|
||||
>
|
||||
<p>Some contents...</p>
|
||||
|
@ -42,18 +42,18 @@ import type { DrawerProps } from 'ant-design-vue';
|
|||
export default defineComponent({
|
||||
setup() {
|
||||
const placement = ref<DrawerProps['placement']>('left');
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
return {
|
||||
placement,
|
||||
visible,
|
||||
open,
|
||||
showDrawer,
|
||||
onClose,
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ Render in current dom. custom container, check `getContainer`.
|
|||
title="Basic Drawer"
|
||||
placement="right"
|
||||
:closable="false"
|
||||
:visible="visible"
|
||||
:open="open"
|
||||
:get-container="false"
|
||||
:style="{ position: 'absolute' }"
|
||||
@close="onClose"
|
||||
|
@ -51,23 +51,23 @@ Render in current dom. custom container, check `getContainer`.
|
|||
import { defineComponent, ref } from 'vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const visible = ref(false);
|
||||
const open = ref(false);
|
||||
|
||||
const afterVisibleChange = (bool: boolean) => {
|
||||
console.log('visible', bool);
|
||||
const afterOpenChange = (bool: boolean) => {
|
||||
console.log('open', bool);
|
||||
};
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
return {
|
||||
visible,
|
||||
afterVisibleChange,
|
||||
open,
|
||||
afterOpenChange,
|
||||
showDrawer,
|
||||
onClose,
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ The default width (or height) of Drawer is `378px`, and there is a presetted lar
|
|||
Open Default Size (378px)
|
||||
</a-button>
|
||||
<a-button type="primary" @click="showDrawer('large')">Open Large Size (736px)</a-button>
|
||||
<a-drawer title="Basic Drawer" :size="size" :visible="visible" @close="onClose">
|
||||
<a-drawer title="Basic Drawer" :size="size" :open="open" @close="onClose">
|
||||
<template #extra>
|
||||
<a-button style="margin-right: 8px" @click="onClose">Cancel</a-button>
|
||||
<a-button type="primary" @click="onClose">Submit</a-button>
|
||||
|
@ -36,19 +36,19 @@ import { defineComponent, ref } from 'vue';
|
|||
import type { DrawerProps } from 'ant-design-vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
const size = ref<DrawerProps['size']>('default');
|
||||
|
||||
const showDrawer = (val: DrawerProps['size']) => {
|
||||
size.value = val;
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
return {
|
||||
visible,
|
||||
open,
|
||||
size,
|
||||
showDrawer,
|
||||
onClose,
|
||||
|
|
|
@ -42,7 +42,7 @@ Use Drawer to quickly preview details of an object, such as those in a list.
|
|||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
<a-drawer width="640" placement="right" :closable="false" :visible="visible" @close="onClose">
|
||||
<a-drawer width="640" placement="right" :closable="false" :open="open" @close="onClose">
|
||||
<p :style="[pStyle, pStyle2]">User Profile</p>
|
||||
<p :style="pStyle">Personal</p>
|
||||
<a-row>
|
||||
|
@ -136,7 +136,7 @@ export default defineComponent({
|
|||
descriptionItem,
|
||||
},
|
||||
setup() {
|
||||
const visible = ref<boolean>(false);
|
||||
const open = ref<boolean>(false);
|
||||
const pStyle = {
|
||||
fontSize: '16px',
|
||||
color: 'rgba(0,0,0,0.85)',
|
||||
|
@ -149,13 +149,13 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const showDrawer = () => {
|
||||
visible.value = true;
|
||||
open.value = true;
|
||||
};
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
open.value = false;
|
||||
};
|
||||
return {
|
||||
visible,
|
||||
open,
|
||||
pStyle,
|
||||
pStyle2,
|
||||
showDrawer,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
category: Components
|
||||
type: Feedback
|
||||
title: Drawer
|
||||
cover: https://img.alicdn.com/imgextra/i4/O1CN019djdZP1OHwXSRGCOW_!!6000000001681-55-tps-161-117.svg
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*v3TvSq2E0HAAAAAAAAAAAAAADrJ8AQ/original
|
||||
---
|
||||
|
||||
A panel which slides in from the edge of the screen.
|
||||
|
@ -17,16 +17,17 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
|||
|
||||
## API
|
||||
|
||||
**🚨 Note:** v4 use `rootClassName` & `rootStyle` to config wrapper style instead of `class` & `style` in v4 to align the API with Modal.
|
||||
|
||||
| Props | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autofocus | Whether Drawer should get focused after open | boolean | true | 3.0.0 |
|
||||
| bodyStyle | Style of the drawer content part | CSSProperties | - | |
|
||||
| class | The class name of the container of the Drawer dialog | string | - | |
|
||||
| class | Config Drawer Panel className. Use `rootClassName` if want to config top dom style | string | - | |
|
||||
| closable | Whether a close (x) button is visible on top left of the Drawer dialog or not | boolean | true | |
|
||||
| closeIcon | Custom close icon | VNode \| slot | `<CloseOutlined />` | 3.0.0 |
|
||||
| contentWrapperStyle | Style of the drawer wrapper of content part | CSSProperties | - | 3.0.0 |
|
||||
| destroyOnClose | Whether to unmount child components on closing drawer or not | boolean | false | |
|
||||
| drawerStyle | Style of the popup layer element | CSSProperties | - | |
|
||||
| extra | Extra actions area at corner | VNode \| slot | - | 3.0.0 |
|
||||
| footer | The footer for Drawer | VNode \| slot | - | 3.0.0 |
|
||||
| footerStyle | Style of the drawer footer part | CSSProperties | - | 3.0.0 |
|
||||
|
@ -40,10 +41,13 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
|||
| maskStyle | Style for Drawer's mask element | CSSProperties | {} | |
|
||||
| placement | The placement of the Drawer | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' | |
|
||||
| push | Nested drawers push behavior | boolean \| {distance: string \| number} | { distance: 180 } | 3.0.0 |
|
||||
| rootClassName | The class name of the container of the Drawer dialog | string | - | 4.0 |
|
||||
| rootStyle | Style of wrapper element which **contains mask** compare to `style` | CSSProperties | - | 4.0 |
|
||||
| style | Style of Drawer panel. Use `bodyStyle` if want to config body only | CSSProperties | - | |
|
||||
| size | presetted size of drawer, default `378px` and large `736px` | `default` \| `large` | `default` | 3.0.0 |
|
||||
| style | Style of wrapper element which contains mask compare to drawerStyle | CSSProperties | - | |
|
||||
| title | The title for Drawer | string \| slot | - | |
|
||||
| visible(v-model) | Whether the Drawer dialog is visible or not | boolean | - | |
|
||||
| open(v-model) | Whether the Drawer dialog is visible or not | boolean | - | 4.0 |
|
||||
| width | Width of the Drawer dialog | string \| number | 378 | |
|
||||
| zIndex | The `z-index` of the Drawer | Number | 1000 | |
|
||||
|
||||
|
@ -51,5 +55,5 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
|||
|
||||
| Name | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| afterVisibleChange | Callback after the animation ends when switching drawers. | function(visible) | - | |
|
||||
| afterOpenChange | Callback after the animation ends when switching drawers. | function(open) | - | 4.0 |
|
||||
| close | Specify a callback that will be called when a user clicks mask, close button or Cancel button. | function(e) | - | |
|
||||
|
|
|
@ -16,17 +16,22 @@ import VcDrawer from '../vc-drawer';
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import { tuple, withInstall } from '../_util/type';
|
||||
import { objectType, withInstall } from '../_util/type';
|
||||
import omit from '../_util/omit';
|
||||
import devWarning from '../vc-util/devWarning';
|
||||
import type { KeyboardEventHandler, MouseEventHandler } from '../_util/EventInterface';
|
||||
import useStyle from './style';
|
||||
import { NoCompactStyle } from '../space/Compact';
|
||||
|
||||
import isNumeric from '../_util/isNumeric';
|
||||
import { getTransitionName, getTransitionProps } from '../_util/transition';
|
||||
|
||||
type ILevelMove = number | [number, number];
|
||||
|
||||
const PlacementTypes = tuple('top', 'right', 'bottom', 'left');
|
||||
const PlacementTypes = ['top', 'right', 'bottom', 'left'] as const;
|
||||
export type placementType = (typeof PlacementTypes)[number];
|
||||
|
||||
const SizeTypes = tuple('default', 'large');
|
||||
const SizeTypes = ['default', 'large'] as const;
|
||||
export type sizeType = (typeof SizeTypes)[number];
|
||||
|
||||
export interface PushState {
|
||||
|
@ -49,25 +54,23 @@ export const drawerProps = () => ({
|
|||
},
|
||||
maskClosable: { type: Boolean, default: undefined },
|
||||
mask: { type: Boolean, default: undefined },
|
||||
maskStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
/** @deprecated Use `style` instead */
|
||||
wrapStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
style: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
class: PropTypes.any,
|
||||
/** @deprecated Use `class` instead */
|
||||
wrapClassName: String,
|
||||
maskStyle: objectType<CSSProperties>(),
|
||||
rootClassName: String,
|
||||
rootStyle: objectType<CSSProperties>(),
|
||||
size: {
|
||||
type: String as PropType<sizeType>,
|
||||
},
|
||||
drawerStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
headerStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
bodyStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
drawerStyle: objectType<CSSProperties>(),
|
||||
headerStyle: objectType<CSSProperties>(),
|
||||
bodyStyle: objectType<CSSProperties>(),
|
||||
contentWrapperStyle: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: undefined as CSSProperties,
|
||||
},
|
||||
title: PropTypes.any,
|
||||
/** @deprecated Please use `open` instead */
|
||||
visible: { type: Boolean, default: undefined },
|
||||
open: { type: Boolean, default: undefined },
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
zIndex: Number,
|
||||
|
@ -77,7 +80,7 @@ export const drawerProps = () => ({
|
|||
keyboard: { type: Boolean, default: undefined },
|
||||
extra: PropTypes.any,
|
||||
footer: PropTypes.any,
|
||||
footerStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
footerStyle: objectType<CSSProperties>(),
|
||||
level: PropTypes.any,
|
||||
levelMove: {
|
||||
type: [Number, Array, Function] as PropType<
|
||||
|
@ -87,8 +90,12 @@ export const drawerProps = () => ({
|
|||
handle: PropTypes.any,
|
||||
/** @deprecated Use `@afterVisibleChange` instead */
|
||||
afterVisibleChange: Function as PropType<(visible: boolean) => void>,
|
||||
/** @deprecated Please use `@afterOpenChange` instead */
|
||||
onAfterVisibleChange: Function as PropType<(visible: boolean) => void>,
|
||||
onAfterOpenChange: Function as PropType<(open: boolean) => void>,
|
||||
/** @deprecated Please use `onUpdate:open` instead */
|
||||
'onUpdate:visible': Function as PropType<(visible: boolean) => void>,
|
||||
'onUpdate:open': Function as PropType<(open: boolean) => void>,
|
||||
onClose: Function as PropType<MouseEventHandler | KeyboardEventHandler>,
|
||||
});
|
||||
|
||||
|
@ -100,7 +107,7 @@ const Drawer = defineComponent({
|
|||
inheritAttrs: false,
|
||||
props: initDefaultProps(drawerProps(), {
|
||||
closable: true,
|
||||
placement: 'right' as placementType,
|
||||
placement: 'right',
|
||||
maskClosable: true,
|
||||
mask: true,
|
||||
level: null,
|
||||
|
@ -115,11 +122,11 @@ const Drawer = defineComponent({
|
|||
const vcDrawer = ref(null);
|
||||
const load = ref(false);
|
||||
const visible = ref(false);
|
||||
|
||||
const mergedOpen = computed(() => props.open ?? props.visible);
|
||||
watch(
|
||||
() => props.visible,
|
||||
propsVisible => {
|
||||
if (propsVisible) {
|
||||
mergedOpen,
|
||||
() => {
|
||||
if (mergedOpen.value) {
|
||||
load.value = true;
|
||||
} else {
|
||||
visible.value = false;
|
||||
|
@ -128,9 +135,9 @@ const Drawer = defineComponent({
|
|||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
[() => props.visible, load],
|
||||
([propsVisible]) => {
|
||||
if (propsVisible && load.value) {
|
||||
[mergedOpen, load],
|
||||
() => {
|
||||
if (mergedOpen.value && load.value) {
|
||||
visible.value = true;
|
||||
}
|
||||
},
|
||||
|
@ -138,6 +145,7 @@ const Drawer = defineComponent({
|
|||
);
|
||||
const parentDrawerOpts = inject('parentDrawerOpts', null);
|
||||
const { prefixCls, getPopupContainer, direction } = useConfigInject('drawer', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const getContainer = computed(() =>
|
||||
// 有可能为 false,所以不能直接判断
|
||||
props.getContainer === undefined && getPopupContainer.value
|
||||
|
@ -150,16 +158,21 @@ const Drawer = defineComponent({
|
|||
'Drawer',
|
||||
'`afterVisibleChange` prop is deprecated, please use `@afterVisibleChange` event instead',
|
||||
);
|
||||
devWarning(
|
||||
props.wrapStyle === undefined,
|
||||
'Drawer',
|
||||
'`wrapStyle` prop is deprecated, please use `style` instead',
|
||||
);
|
||||
devWarning(
|
||||
props.wrapClassName === undefined,
|
||||
'Drawer',
|
||||
'`wrapClassName` prop is deprecated, please use `class` instead',
|
||||
);
|
||||
// ========================== Warning ===========================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onUpdate:visible', 'onUpdate:open'],
|
||||
['onAfterVisibleChange', 'onAfterOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
devWarning(
|
||||
!props[deprecatedName],
|
||||
'Drawer',
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const setPush = () => {
|
||||
sPush.value = true;
|
||||
};
|
||||
|
@ -176,7 +189,7 @@ const Drawer = defineComponent({
|
|||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (props.visible && parentDrawerOpts) {
|
||||
if (mergedOpen.value && parentDrawerOpts) {
|
||||
parentDrawerOpts.setPush();
|
||||
}
|
||||
});
|
||||
|
@ -207,6 +220,7 @@ const Drawer = defineComponent({
|
|||
|
||||
const close = (e: Event) => {
|
||||
emit('update:visible', false);
|
||||
emit('update:open', false);
|
||||
emit('close', e);
|
||||
};
|
||||
|
||||
|
@ -222,6 +236,7 @@ const Drawer = defineComponent({
|
|||
}
|
||||
props.afterVisibleChange?.(open);
|
||||
emit('afterVisibleChange', open);
|
||||
emit('afterOpenChange', open);
|
||||
};
|
||||
|
||||
const pushTransform = computed(() => {
|
||||
|
@ -243,36 +258,28 @@ const Drawer = defineComponent({
|
|||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
// ============================ Size ============================
|
||||
const mergedWidth = computed(() => props.width ?? (props.size === 'large' ? 736 : 378));
|
||||
const mergedHeight = computed(() => props.height ?? (props.size === 'large' ? 736 : 378));
|
||||
const offsetStyle = computed(() => {
|
||||
// https://github.com/ant-design/ant-design/issues/24287
|
||||
const { mask, placement, size = 'default', width, height } = props;
|
||||
const { mask, placement } = props;
|
||||
if (!visible.value && !mask) {
|
||||
return {};
|
||||
}
|
||||
const val: CSSProperties = {};
|
||||
if (placement === 'left' || placement === 'right') {
|
||||
const defaultWidth = size === 'large' ? 736 : 378;
|
||||
val.width = typeof width === 'undefined' ? defaultWidth : width;
|
||||
val.width = typeof val.width === 'string' ? val.width : `${val.width}px`;
|
||||
val.width = isNumeric(mergedWidth.value) ? `${mergedWidth.value}px` : mergedWidth.value;
|
||||
} else {
|
||||
const defaultHeight = size === 'large' ? 736 : 378;
|
||||
val.height = typeof height === 'undefined' ? defaultHeight : height;
|
||||
val.height = typeof val.height === 'string' ? val.height : `${val.height}px`;
|
||||
val.height = isNumeric(mergedHeight.value) ? `${mergedHeight.value}px` : mergedHeight.value;
|
||||
}
|
||||
return val;
|
||||
});
|
||||
|
||||
const drawerStyle = computed(() => {
|
||||
const { zIndex, wrapStyle, mask, style } = props;
|
||||
const val = mask ? {} : offsetStyle.value;
|
||||
return {
|
||||
zIndex,
|
||||
transform: sPush.value ? pushTransform.value : undefined,
|
||||
...val,
|
||||
...wrapStyle,
|
||||
...style,
|
||||
};
|
||||
const wrapperStyle = computed(() => {
|
||||
const { zIndex } = props;
|
||||
const val = offsetStyle.value;
|
||||
return [{ zIndex, transform: sPush.value ? pushTransform.value : undefined }, val];
|
||||
});
|
||||
|
||||
const renderHeader = (prefixCls: string) => {
|
||||
|
@ -342,21 +349,29 @@ const Drawer = defineComponent({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
const drawerClassName = computed(() =>
|
||||
classnames(
|
||||
{
|
||||
'no-mask': !props.mask,
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
},
|
||||
props.rootClassName,
|
||||
hashId.value,
|
||||
),
|
||||
);
|
||||
// =========================== Motion ===========================
|
||||
const maskMotion = computed(() => {
|
||||
return getTransitionProps(getTransitionName(prefixCls.value, 'mask-motion'));
|
||||
});
|
||||
const panelMotion = (motionPlacement: string) => {
|
||||
return getTransitionProps(
|
||||
getTransitionName(prefixCls.value, `panel-motion-${motionPlacement}`),
|
||||
);
|
||||
};
|
||||
|
||||
return () => {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
placement,
|
||||
mask,
|
||||
wrapClassName,
|
||||
class: className,
|
||||
forceRender,
|
||||
...rest
|
||||
} = props;
|
||||
const { width, height, placement, mask, forceRender, ...rest } = props;
|
||||
|
||||
const val = mask ? offsetStyle.value : {};
|
||||
const haveMask = mask ? '' : 'no-mask';
|
||||
const vcDrawerProps: any = {
|
||||
...attrs,
|
||||
...omit(rest, [
|
||||
|
@ -369,13 +384,12 @@ const Drawer = defineComponent({
|
|||
'bodyStyle',
|
||||
'title',
|
||||
'push',
|
||||
'wrapStyle',
|
||||
'onAfterVisibleChange',
|
||||
'onClose',
|
||||
'onUpdate:visible',
|
||||
'onUpdate:open',
|
||||
'visible',
|
||||
]),
|
||||
...val,
|
||||
forceRender,
|
||||
onClose: close,
|
||||
afterVisibleChange,
|
||||
|
@ -384,24 +398,26 @@ const Drawer = defineComponent({
|
|||
open: visible.value,
|
||||
showMask: mask,
|
||||
placement,
|
||||
class: classnames({
|
||||
[className]: className,
|
||||
[wrapClassName]: !!wrapClassName,
|
||||
[haveMask]: !!haveMask,
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
}),
|
||||
style: drawerStyle.value,
|
||||
ref: vcDrawer,
|
||||
};
|
||||
return (
|
||||
<VcDrawer
|
||||
{...vcDrawerProps}
|
||||
getContainer={getContainer.value}
|
||||
v-slots={{
|
||||
handler: props.handle ? () => props.handle : slots.handle,
|
||||
default: () => renderBody(prefixCls.value),
|
||||
}}
|
||||
></VcDrawer>
|
||||
return wrapSSR(
|
||||
<NoCompactStyle>
|
||||
<VcDrawer
|
||||
{...vcDrawerProps}
|
||||
maskMotion={maskMotion.value}
|
||||
motion={panelMotion}
|
||||
width={mergedWidth.value}
|
||||
height={mergedHeight.value}
|
||||
getContainer={getContainer.value}
|
||||
rootClassName={drawerClassName.value}
|
||||
rootStyle={props.rootStyle}
|
||||
contentWrapperStyle={wrapperStyle.value}
|
||||
v-slots={{
|
||||
handler: props.handle ? () => props.handle : slots.handle,
|
||||
default: () => renderBody(prefixCls.value),
|
||||
}}
|
||||
></VcDrawer>
|
||||
</NoCompactStyle>,
|
||||
);
|
||||
};
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ category: Components
|
|||
type: 反馈
|
||||
title: Drawer
|
||||
subtitle: 抽屉
|
||||
cover: https://img.alicdn.com/imgextra/i4/O1CN019djdZP1OHwXSRGCOW_!!6000000001681-55-tps-161-117.svg
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*v3TvSq2E0HAAAAAAAAAAAAAADrJ8AQ/original
|
||||
---
|
||||
|
||||
屏幕边缘滑出的浮层面板。
|
||||
|
@ -17,16 +17,17 @@ cover: https://img.alicdn.com/imgextra/i4/O1CN019djdZP1OHwXSRGCOW_!!600000000168
|
|||
|
||||
## API
|
||||
|
||||
**🚨 注意:** v4 使用 `rootClassName` 与 `rootStyle` 来配置最外层元素样式。原 v4 `class` 与 `style` 改至配置 Drawer 窗体样式以和 Modal 对齐。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| autofocus | 抽屉展开后是否将焦点切换至其 Dom 节点 | boolean | true | 3.0.0 |
|
||||
| bodyStyle | 可用于设置 Drawer 内容部分的样式 | CSSProperties | - | |
|
||||
| class | 对话框外层容器的类名 | string | - | |
|
||||
| class | Drawer 容器外层 className 设置,如果需要设置最外层,请使用 rootClassName | string | - | |
|
||||
| closable | 是否显示左上角的关闭按钮 | boolean | true | |
|
||||
| closeIcon | 自定义关闭图标 | VNode \| slot | `<CloseOutlined />` | 3.0.0 |
|
||||
| contentWrapperStyle | 可用于设置 Drawer 包裹内容部分的样式 | CSSProperties | - | 3.0.0 |
|
||||
| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false | |
|
||||
| drawerStyle | 用于设置 Drawer 弹出层的样式 | object | - | |
|
||||
| extra | 抽屉右上角的操作区域 | VNode \| slot | - | 3.0.0 |
|
||||
| footer | 抽屉的页脚 | VNode \| slot | - | 3.0.0 |
|
||||
| footerStyle | 抽屉页脚部件的样式 | CSSProperties | - | 3.0.0 |
|
||||
|
@ -40,16 +41,18 @@ cover: https://img.alicdn.com/imgextra/i4/O1CN019djdZP1OHwXSRGCOW_!!600000000168
|
|||
| maskStyle | 遮罩样式 | CSSProperties | {} | |
|
||||
| placement | 抽屉的方向 | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' | |
|
||||
| push | 用于设置多层 Drawer 的推动行为 | boolean \| {distance: string \| number} | { distance: 180 } | 3.0.0 |
|
||||
| rootClassName | 对话框外层容器的类名 | string | - | 4.0 |
|
||||
| rootStyle | 可用于设置 Drawer 最外层容器的样式,和 `style` 的区别是作用节点包括 `mask` | CSSProperties | - | 4.0 |
|
||||
| size | 预设抽屉宽度(或高度),default `378px` 和 large `736px` | `default` \| `large` | `default` | 3.0.0 |
|
||||
| style | 可用于设置 Drawer 最外层容器的样式,和 `drawerStyle` 的区别是作用节点包括 `mask` | CSSProperties | - | |
|
||||
| style | 设计 Drawer 容器样式,如果你只需要设置内容部分请使用 `bodyStyle` | CSSProperties | - | |
|
||||
| title | 标题 | string \| slot | - | |
|
||||
| visible(v-model) | Drawer 是否可见 | boolean | - | |
|
||||
| open(v-model) | Drawer 是否可见 | boolean | - | 4.0 |
|
||||
| width | 宽度 | string \| number | 378 | |
|
||||
| zIndex | 设置 Drawer 的 `z-index` | Number | 1000 | |
|
||||
|
||||
## 事件
|
||||
|
||||
| 名称 | 描述 | 类型 | 默认值 | 版本 |
|
||||
| ------------------ | ------------------------------------ | ----------------- | ------ | ---- |
|
||||
| afterVisibleChange | 切换抽屉时动画结束后的回调 | function(visible) | 无 | |
|
||||
| close | 点击遮罩层或左上角叉或取消按钮的回调 | function(e) | 无 | |
|
||||
| 名称 | 描述 | 类型 | 默认值 | 版本 |
|
||||
| --------------- | ------------------------------------ | -------------- | ------ | ---- |
|
||||
| afterOpenChange | 切换抽屉时动画结束后的回调 | function(open) | 无 | 4.0 |
|
||||
| close | 点击遮罩层或左上角叉或取消按钮的回调 | function(e) | 无 | |
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
|
||||
@drawer-prefix-cls: ~'@{ant-prefix}-drawer';
|
||||
@picker-prefix-cls: ~'@{ant-prefix}-picker';
|
||||
@drawer-animation-ease: @ease-out-quint;
|
||||
|
||||
.@{drawer-prefix-cls} {
|
||||
@drawer-header-close-padding: ceil(((@drawer-header-close-size - @font-size-lg) / 2));
|
||||
|
||||
position: fixed;
|
||||
z-index: @zindex-modal;
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
transition: width 0s ease @animation-duration-slow, height 0s ease @animation-duration-slow;
|
||||
|
||||
&-content-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform @animation-duration-slow @drawer-animation-ease,
|
||||
box-shadow @animation-duration-slow @drawer-animation-ease;
|
||||
}
|
||||
|
||||
.@{drawer-prefix-cls}-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
top: 0;
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
width: 100%;
|
||||
transition: transform @animation-duration-slow @drawer-animation-ease;
|
||||
}
|
||||
}
|
||||
|
||||
&-left {
|
||||
left: 0;
|
||||
|
||||
.@{drawer-prefix-cls} {
|
||||
&-content-wrapper {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
box-shadow: @shadow-1-right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
right: 0;
|
||||
|
||||
.@{drawer-prefix-cls} {
|
||||
&-content-wrapper {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
box-shadow: @shadow-1-left;
|
||||
}
|
||||
// https://github.com/ant-design/ant-design/issues/18607, Avoid edge alignment bug.
|
||||
&.no-mask {
|
||||
right: 1px;
|
||||
transform: translateX(1px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-top,
|
||||
&-bottom {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0%;
|
||||
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
height: 100%;
|
||||
transition: transform @animation-duration-slow @drawer-animation-ease;
|
||||
}
|
||||
}
|
||||
|
||||
&-top {
|
||||
top: 0;
|
||||
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
box-shadow: @shadow-1-down;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-bottom {
|
||||
bottom: 0;
|
||||
|
||||
.@{drawer-prefix-cls} {
|
||||
&-content-wrapper {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
&.@{drawer-prefix-cls}-open {
|
||||
.@{drawer-prefix-cls}-content-wrapper {
|
||||
box-shadow: @shadow-1-up;
|
||||
}
|
||||
|
||||
&.no-mask {
|
||||
bottom: 1px;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.@{drawer-prefix-cls}-open .@{drawer-prefix-cls}-mask {
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
transition: none;
|
||||
animation: antdDrawerFadeIn @animation-duration-slow @drawer-animation-ease;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&-title {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
color: @heading-color;
|
||||
font-weight: 500;
|
||||
font-size: @drawer-title-font-size;
|
||||
line-height: @drawer-title-line-height;
|
||||
}
|
||||
|
||||
&-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: auto;
|
||||
background-color: @drawer-bg;
|
||||
background-clip: padding-box;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&-close {
|
||||
display: inline-block;
|
||||
margin-right: 12px;
|
||||
color: @modal-close-color;
|
||||
font-weight: 700;
|
||||
font-size: @font-size-lg;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
transition: color @animation-duration-slow;
|
||||
text-rendering: auto;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
color: @icon-color-hover;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: @drawer-header-padding;
|
||||
color: @text-color;
|
||||
background: @drawer-bg;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-close-only {
|
||||
padding-bottom: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-wrapper-body {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-body {
|
||||
flex-grow: 1;
|
||||
padding: @drawer-body-padding;
|
||||
overflow: auto;
|
||||
font-size: @font-size-base;
|
||||
line-height: @line-height-base;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
flex-shrink: 0;
|
||||
padding: @drawer-footer-padding-vertical @drawer-footer-padding-horizontal;
|
||||
border-top: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
&-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background-color: @modal-mask-bg;
|
||||
opacity: 0;
|
||||
transition: opacity @animation-duration-slow linear, height 0s ease @animation-duration-slow;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// =================== Hook Components ===================
|
||||
.@{picker-prefix-cls} {
|
||||
&-clear {
|
||||
background: @popover-background;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antdDrawerFadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
@import './drawer';
|
||||
@import './rtl';
|
||||
|
||||
.popover-customize-bg(@drawer-prefix-cls, @popover-background);
|
|
@ -0,0 +1,230 @@
|
|||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import genMotionStyle from './motion';
|
||||
|
||||
export interface ComponentToken {
|
||||
zIndexPopup: number;
|
||||
}
|
||||
|
||||
export interface DrawerToken extends FullToken<'Drawer'> {
|
||||
drawerFooterPaddingVertical: number;
|
||||
drawerFooterPaddingHorizontal: number;
|
||||
}
|
||||
|
||||
// =============================== Base ===============================
|
||||
const genDrawerStyle: GenerateStyle<DrawerToken> = (token: DrawerToken) => {
|
||||
const {
|
||||
componentCls,
|
||||
zIndexPopup,
|
||||
colorBgMask,
|
||||
colorBgElevated,
|
||||
motionDurationSlow,
|
||||
motionDurationMid,
|
||||
padding,
|
||||
paddingLG,
|
||||
fontSizeLG,
|
||||
lineHeightLG,
|
||||
lineWidth,
|
||||
lineType,
|
||||
colorSplit,
|
||||
marginSM,
|
||||
colorIcon,
|
||||
colorIconHover,
|
||||
colorText,
|
||||
fontWeightStrong,
|
||||
drawerFooterPaddingVertical,
|
||||
drawerFooterPaddingHorizontal,
|
||||
} = token;
|
||||
|
||||
const wrapperCls = `${componentCls}-content-wrapper`;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
zIndex: zIndexPopup,
|
||||
pointerEvents: 'none',
|
||||
|
||||
'&-pure': {
|
||||
position: 'relative',
|
||||
background: colorBgElevated,
|
||||
|
||||
[`&${componentCls}-left`]: {
|
||||
boxShadow: token.boxShadowDrawerLeft,
|
||||
},
|
||||
[`&${componentCls}-right`]: {
|
||||
boxShadow: token.boxShadowDrawerRight,
|
||||
},
|
||||
[`&${componentCls}-top`]: {
|
||||
boxShadow: token.boxShadowDrawerUp,
|
||||
},
|
||||
[`&${componentCls}-bottom`]: {
|
||||
boxShadow: token.boxShadowDrawerDown,
|
||||
},
|
||||
},
|
||||
|
||||
'&-inline': {
|
||||
position: 'absolute',
|
||||
},
|
||||
|
||||
// ====================== Mask ======================
|
||||
[`${componentCls}-mask`]: {
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
zIndex: zIndexPopup,
|
||||
background: colorBgMask,
|
||||
pointerEvents: 'auto',
|
||||
},
|
||||
|
||||
// ==================== Content =====================
|
||||
[wrapperCls]: {
|
||||
position: 'absolute',
|
||||
zIndex: zIndexPopup,
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
|
||||
'&-hidden': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
|
||||
// Placement
|
||||
[`&-left > ${wrapperCls}`]: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: 0,
|
||||
},
|
||||
boxShadow: token.boxShadowDrawerLeft,
|
||||
},
|
||||
[`&-right > ${wrapperCls}`]: {
|
||||
top: 0,
|
||||
right: {
|
||||
_skip_check_: true,
|
||||
value: 0,
|
||||
},
|
||||
bottom: 0,
|
||||
boxShadow: token.boxShadowDrawerRight,
|
||||
},
|
||||
[`&-top > ${wrapperCls}`]: {
|
||||
top: 0,
|
||||
insetInline: 0,
|
||||
boxShadow: token.boxShadowDrawerUp,
|
||||
},
|
||||
[`&-bottom > ${wrapperCls}`]: {
|
||||
bottom: 0,
|
||||
insetInline: 0,
|
||||
boxShadow: token.boxShadowDrawerDown,
|
||||
},
|
||||
|
||||
[`${componentCls}-content`]: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
background: colorBgElevated,
|
||||
pointerEvents: 'auto',
|
||||
},
|
||||
|
||||
// ===================== Panel ======================
|
||||
[`${componentCls}-wrapper-body`]: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
|
||||
// Header
|
||||
[`${componentCls}-header`]: {
|
||||
display: 'flex',
|
||||
flex: 0,
|
||||
alignItems: 'center',
|
||||
padding: `${padding}px ${paddingLG}px`,
|
||||
fontSize: fontSizeLG,
|
||||
lineHeight: lineHeightLG,
|
||||
borderBottom: `${lineWidth}px ${lineType} ${colorSplit}`,
|
||||
|
||||
'&-title': {
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
minWidth: 0,
|
||||
minHeight: 0,
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-extra`]: {
|
||||
flex: 'none',
|
||||
},
|
||||
|
||||
[`${componentCls}-close`]: {
|
||||
display: 'inline-block',
|
||||
marginInlineEnd: marginSM,
|
||||
color: colorIcon,
|
||||
fontWeight: fontWeightStrong,
|
||||
fontSize: fontSizeLG,
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1,
|
||||
textAlign: 'center',
|
||||
textTransform: 'none',
|
||||
textDecoration: 'none',
|
||||
background: 'transparent',
|
||||
border: 0,
|
||||
outline: 0,
|
||||
cursor: 'pointer',
|
||||
transition: `color ${motionDurationMid}`,
|
||||
textRendering: 'auto',
|
||||
|
||||
'&:focus, &:hover': {
|
||||
color: colorIconHover,
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-title`]: {
|
||||
flex: 1,
|
||||
margin: 0,
|
||||
color: colorText,
|
||||
fontWeight: token.fontWeightStrong,
|
||||
fontSize: fontSizeLG,
|
||||
lineHeight: lineHeightLG,
|
||||
},
|
||||
|
||||
// Body
|
||||
[`${componentCls}-body`]: {
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
minHeight: 0,
|
||||
padding: paddingLG,
|
||||
overflow: 'auto',
|
||||
},
|
||||
|
||||
// Footer
|
||||
[`${componentCls}-footer`]: {
|
||||
flexShrink: 0,
|
||||
padding: `${drawerFooterPaddingVertical}px ${drawerFooterPaddingHorizontal}px`,
|
||||
borderTop: `${lineWidth}px ${lineType} ${colorSplit}`,
|
||||
},
|
||||
|
||||
// ====================== RTL =======================
|
||||
'&-rtl': {
|
||||
direction: 'rtl',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook(
|
||||
'Drawer',
|
||||
token => {
|
||||
const drawerToken = mergeToken<DrawerToken>(token, {
|
||||
drawerFooterPaddingVertical: token.paddingXS,
|
||||
drawerFooterPaddingHorizontal: token.padding,
|
||||
});
|
||||
|
||||
return [genDrawerStyle(drawerToken), genMotionStyle(drawerToken)];
|
||||
},
|
||||
token => ({
|
||||
zIndexPopup: token.zIndexPopupBase,
|
||||
}),
|
||||
);
|
|
@ -1,3 +0,0 @@
|
|||
// deps-lint-skip: empty
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
|
@ -0,0 +1,134 @@
|
|||
import type { DrawerToken } from '.';
|
||||
import type { GenerateStyle } from '../../theme/internal';
|
||||
|
||||
const genMotionStyle: GenerateStyle<DrawerToken> = (token: DrawerToken) => {
|
||||
const { componentCls, motionDurationSlow } = token;
|
||||
|
||||
const sharedPanelMotion = {
|
||||
'&-enter, &-appear, &-leave': {
|
||||
'&-start': {
|
||||
transition: 'none',
|
||||
},
|
||||
|
||||
'&-active': {
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
// ======================== Mask ========================
|
||||
[`${componentCls}-mask-motion`]: {
|
||||
'&-enter, &-appear, &-leave': {
|
||||
'&-active': {
|
||||
transition: `all ${motionDurationSlow}`,
|
||||
},
|
||||
},
|
||||
|
||||
'&-enter, &-appear': {
|
||||
opacity: 0,
|
||||
'&-active': {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
|
||||
'&-leave': {
|
||||
opacity: 1,
|
||||
'&-active': {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ======================= Panel ========================
|
||||
[`${componentCls}-panel-motion`]: {
|
||||
// Left
|
||||
'&-left': [
|
||||
sharedPanelMotion,
|
||||
{
|
||||
'&-enter, &-appear': {
|
||||
'&-start': {
|
||||
transform: 'translateX(-100%) !important',
|
||||
},
|
||||
'&-active': {
|
||||
transform: 'translateX(0)',
|
||||
},
|
||||
},
|
||||
'&-leave': {
|
||||
transform: 'translateX(0)',
|
||||
'&-active': {
|
||||
transform: 'translateX(-100%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Right
|
||||
'&-right': [
|
||||
sharedPanelMotion,
|
||||
{
|
||||
'&-enter, &-appear': {
|
||||
'&-start': {
|
||||
transform: 'translateX(100%) !important',
|
||||
},
|
||||
'&-active': {
|
||||
transform: 'translateX(0)',
|
||||
},
|
||||
},
|
||||
'&-leave': {
|
||||
transform: 'translateX(0)',
|
||||
'&-active': {
|
||||
transform: 'translateX(100%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Top
|
||||
'&-top': [
|
||||
sharedPanelMotion,
|
||||
{
|
||||
'&-enter, &-appear': {
|
||||
'&-start': {
|
||||
transform: 'translateY(-100%) !important',
|
||||
},
|
||||
'&-active': {
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
},
|
||||
'&-leave': {
|
||||
transform: 'translateY(0)',
|
||||
'&-active': {
|
||||
transform: 'translateY(-100%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Bottom
|
||||
'&-bottom': [
|
||||
sharedPanelMotion,
|
||||
{
|
||||
'&-enter, &-appear': {
|
||||
'&-start': {
|
||||
transform: 'translateY(100%) !important',
|
||||
},
|
||||
'&-active': {
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
},
|
||||
'&-leave': {
|
||||
transform: 'translateY(0)',
|
||||
'&-active': {
|
||||
transform: 'translateY(100%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default genMotionStyle;
|
|
@ -1,16 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
|
||||
@drawer-prefix-cls: ~'@{ant-prefix}-drawer';
|
||||
|
||||
.@{drawer-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&-close {
|
||||
.@{drawer-prefix-cls}-rtl & {
|
||||
margin-right: 0;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ import './radio/style';
|
|||
// import './anchor/style';
|
||||
// import './list/style';
|
||||
// import './tree-select/style';
|
||||
import './drawer/style';
|
||||
// import './drawer/style';
|
||||
// import './skeleton/style';
|
||||
// import './comment/style';
|
||||
// import './config-provider/style';
|
||||
|
|
|
@ -13,7 +13,7 @@ import type { ComponentToken as CollapseComponentToken } from '../../collapse/st
|
|||
import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style';
|
||||
import type { ComponentToken as DividerComponentToken } from '../../divider/style';
|
||||
import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style';
|
||||
// import type { ComponentToken as DrawerComponentToken } from '../../drawer/style';
|
||||
import type { ComponentToken as DrawerComponentToken } from '../../drawer/style';
|
||||
import type { ComponentToken as EmptyComponentToken } from '../../empty/style';
|
||||
import type { ComponentToken as ImageComponentToken } from '../../image/style';
|
||||
import type { ComponentToken as InputNumberComponentToken } from '../../input-number/style';
|
||||
|
@ -69,7 +69,7 @@ export interface ComponentTokenMap {
|
|||
DatePicker?: DatePickerComponentToken;
|
||||
Descriptions?: {};
|
||||
Divider?: DividerComponentToken;
|
||||
// Drawer?: DrawerComponentToken;
|
||||
Drawer?: DrawerComponentToken;
|
||||
Dropdown?: DropdownComponentToken;
|
||||
Empty?: EmptyComponentToken;
|
||||
// FloatButton?: FloatButtonComponentToken;
|
||||
|
|
|
@ -1,30 +1,9 @@
|
|||
import {
|
||||
defineComponent,
|
||||
reactive,
|
||||
onMounted,
|
||||
computed,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
watch,
|
||||
ref,
|
||||
} from 'vue';
|
||||
import { Transition, defineComponent, onMounted, onUnmounted, nextTick, watch, ref } from 'vue';
|
||||
import classnames from '../../_util/classNames';
|
||||
import getScrollBarSize from '../../_util/getScrollBarSize';
|
||||
import KeyCode from '../../_util/KeyCode';
|
||||
import omit from '../../_util/omit';
|
||||
import supportsPassive from '../../_util/supportsPassive';
|
||||
import { drawerChildProps } from './IDrawerPropTypes';
|
||||
|
||||
import {
|
||||
addEventListener,
|
||||
dataToArray,
|
||||
getTouchParentScroll,
|
||||
isNumeric,
|
||||
removeEventListener,
|
||||
transformArguments,
|
||||
transitionEndFun,
|
||||
windowIsUndefined,
|
||||
} from './utils';
|
||||
import { dataToArray, windowIsUndefined } from './utils';
|
||||
|
||||
const currentDrawer: Record<string, boolean> = {};
|
||||
|
||||
|
@ -32,23 +11,12 @@ export interface scrollLockOptions {
|
|||
container: HTMLElement;
|
||||
}
|
||||
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
const DrawerChild = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
inheritAttrs: false,
|
||||
props: drawerChildProps(),
|
||||
emits: ['close', 'handleClick', 'change'],
|
||||
setup(props, { emit, slots }) {
|
||||
const state = reactive({
|
||||
startPos: {
|
||||
x: null,
|
||||
y: null,
|
||||
} as Point | null,
|
||||
});
|
||||
let timeout;
|
||||
const contentWrapper = ref<HTMLElement>();
|
||||
const dom = ref<HTMLElement>();
|
||||
const maskDom = ref<HTMLElement>();
|
||||
|
@ -61,8 +29,6 @@ const DrawerChild = defineComponent({
|
|||
.replace('.', Math.round(Math.random() * 9).toString()),
|
||||
).toString(16)}`;
|
||||
|
||||
const passive = !windowIsUndefined && supportsPassive ? { passive: false } : false;
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const { open, getContainer, showMask, autofocus } = props;
|
||||
|
@ -72,8 +38,6 @@ const DrawerChild = defineComponent({
|
|||
if (container && container.parentNode === document.body) {
|
||||
currentDrawer[drawerId] = open;
|
||||
}
|
||||
// 默认打开状态时推出 level;
|
||||
openLevelTransition();
|
||||
nextTick(() => {
|
||||
if (autofocus) {
|
||||
domFocus();
|
||||
|
@ -100,7 +64,6 @@ const DrawerChild = defineComponent({
|
|||
if (container && container.parentNode === document.body) {
|
||||
currentDrawer[drawerId] = !!open;
|
||||
}
|
||||
openLevelTransition();
|
||||
if (open) {
|
||||
if (autofocus) {
|
||||
domFocus();
|
||||
|
@ -119,7 +82,6 @@ const DrawerChild = defineComponent({
|
|||
const { open } = props;
|
||||
delete currentDrawer[drawerId];
|
||||
if (open) {
|
||||
setLevelTransform(false);
|
||||
document.body.style.touchAction = '';
|
||||
}
|
||||
props.scrollLocker?.unLock();
|
||||
|
@ -139,42 +101,6 @@ const DrawerChild = defineComponent({
|
|||
dom.value?.focus?.();
|
||||
};
|
||||
|
||||
const removeStartHandler = (e: TouchEvent) => {
|
||||
if (e.touches.length > 1) {
|
||||
// need clear the startPos when another touch event happens
|
||||
state.startPos = null;
|
||||
return;
|
||||
}
|
||||
state.startPos = {
|
||||
x: e.touches[0].clientX,
|
||||
y: e.touches[0].clientY,
|
||||
};
|
||||
};
|
||||
|
||||
const removeMoveHandler = (e: TouchEvent) => {
|
||||
// the startPos may be null or undefined
|
||||
if (e.changedTouches.length > 1 || !state.startPos) {
|
||||
return;
|
||||
}
|
||||
const currentTarget = e.currentTarget as HTMLElement;
|
||||
const differX = e.changedTouches[0].clientX - state.startPos.x;
|
||||
const differY = e.changedTouches[0].clientY - state.startPos.y;
|
||||
if (
|
||||
(currentTarget === maskDom.value ||
|
||||
currentTarget === handlerDom.value ||
|
||||
(currentTarget === contentDom.value &&
|
||||
getTouchParentScroll(currentTarget, e.target as HTMLElement, differX, differY))) &&
|
||||
e.cancelable
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const transitionEnd = (e: TransitionEvent) => {
|
||||
const dom: HTMLElement = e.target as HTMLElement;
|
||||
removeEventListener(dom, transitionEndFun, transitionEnd);
|
||||
dom.style.transition = '';
|
||||
};
|
||||
const onClose = (e: Event) => {
|
||||
emit('close', e);
|
||||
};
|
||||
|
@ -186,208 +112,13 @@ const DrawerChild = defineComponent({
|
|||
}
|
||||
};
|
||||
|
||||
const onWrapperTransitionEnd = (e: TransitionEvent) => {
|
||||
const onAfterVisibleChange = () => {
|
||||
const { open, afterVisibleChange } = props;
|
||||
if (e.target === contentWrapper.value && e.propertyName.match(/transform$/)) {
|
||||
dom.value.style.transition = '';
|
||||
if (!open && getCurrentDrawerSome()) {
|
||||
document.body.style.overflowX = '';
|
||||
if (maskDom.value) {
|
||||
maskDom.value.style.left = '';
|
||||
maskDom.value.style.width = '';
|
||||
}
|
||||
}
|
||||
if (afterVisibleChange) {
|
||||
afterVisibleChange(!!open);
|
||||
}
|
||||
if (afterVisibleChange) {
|
||||
afterVisibleChange(!!open);
|
||||
}
|
||||
};
|
||||
|
||||
const horizontalBoolAndPlacementName = computed(() => {
|
||||
const { placement } = props;
|
||||
const isHorizontal = placement === 'left' || placement === 'right';
|
||||
const placementName = `translate${isHorizontal ? 'X' : 'Y'}`;
|
||||
return {
|
||||
isHorizontal,
|
||||
placementName,
|
||||
};
|
||||
});
|
||||
|
||||
const openLevelTransition = () => {
|
||||
const { open, width, height } = props;
|
||||
const { isHorizontal, placementName } = horizontalBoolAndPlacementName.value;
|
||||
const contentValue = contentDom.value
|
||||
? contentDom.value.getBoundingClientRect()[isHorizontal ? 'width' : 'height']
|
||||
: 0;
|
||||
const value = (isHorizontal ? width : height) || contentValue;
|
||||
setLevelAndScrolling(open, placementName, value);
|
||||
};
|
||||
|
||||
const setLevelTransform = (
|
||||
open?: boolean,
|
||||
placementName?: string,
|
||||
value?: string | number,
|
||||
right?: number,
|
||||
) => {
|
||||
const { placement, levelMove, duration, ease, showMask } = props;
|
||||
// router 切换时可能会导至页面失去滚动条,所以需要时时获取。
|
||||
levelDom.forEach(dom => {
|
||||
dom.style.transition = `transform ${duration} ${ease}`;
|
||||
addEventListener(dom, transitionEndFun, transitionEnd);
|
||||
let levelValue = open ? value : 0;
|
||||
if (levelMove) {
|
||||
const $levelMove = transformArguments(levelMove, { target: dom, open });
|
||||
levelValue = open ? $levelMove[0] : $levelMove[1] || 0;
|
||||
}
|
||||
const $value = typeof levelValue === 'number' ? `${levelValue}px` : levelValue;
|
||||
let placementPos = placement === 'left' || placement === 'top' ? $value : `-${$value}`;
|
||||
placementPos =
|
||||
showMask && placement === 'right' && right
|
||||
? `calc(${placementPos} + ${right}px)`
|
||||
: placementPos;
|
||||
dom.style.transform = levelValue ? `${placementName}(${placementPos})` : '';
|
||||
});
|
||||
};
|
||||
|
||||
const setLevelAndScrolling = (
|
||||
open?: boolean,
|
||||
placementName?: string,
|
||||
value?: string | number,
|
||||
) => {
|
||||
if (!windowIsUndefined) {
|
||||
const right =
|
||||
document.body.scrollHeight >
|
||||
(window.innerHeight || document.documentElement.clientHeight) &&
|
||||
window.innerWidth > document.body.offsetWidth
|
||||
? getScrollBarSize(true)
|
||||
: 0;
|
||||
setLevelTransform(open, placementName, value, right);
|
||||
toggleScrollingToDrawerAndBody(right);
|
||||
}
|
||||
emit('change', open);
|
||||
};
|
||||
|
||||
const toggleScrollingToDrawerAndBody = (right: number) => {
|
||||
const { getContainer, showMask, open } = props;
|
||||
const container = getContainer?.();
|
||||
// 处理 body 滚动
|
||||
if (container && container.parentNode === document.body && showMask) {
|
||||
const eventArray = ['touchstart'];
|
||||
const domArray = [document.body, maskDom.value, handlerDom.value, contentDom.value];
|
||||
if (open && document.body.style.overflow !== 'hidden') {
|
||||
if (right) {
|
||||
addScrollingEffect(right);
|
||||
}
|
||||
document.body.style.touchAction = 'none';
|
||||
// 手机禁滚
|
||||
domArray.forEach((item, i) => {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
addEventListener(
|
||||
item,
|
||||
eventArray[i] || 'touchmove',
|
||||
i ? removeMoveHandler : removeStartHandler,
|
||||
passive,
|
||||
);
|
||||
});
|
||||
} else if (getCurrentDrawerSome()) {
|
||||
document.body.style.touchAction = '';
|
||||
if (right) {
|
||||
remScrollingEffect(right);
|
||||
}
|
||||
// 恢复事件
|
||||
domArray.forEach((item, i) => {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
removeEventListener(
|
||||
item,
|
||||
eventArray[i] || 'touchmove',
|
||||
i ? removeMoveHandler : removeStartHandler,
|
||||
passive,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addScrollingEffect = (right: number) => {
|
||||
const { placement, duration, ease } = props;
|
||||
const widthTransition = `width ${duration} ${ease}`;
|
||||
const transformTransition = `transform ${duration} ${ease}`;
|
||||
dom.value.style.transition = 'none';
|
||||
switch (placement) {
|
||||
case 'right':
|
||||
dom.value.style.transform = `translateX(-${right}px)`;
|
||||
break;
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
dom.value.style.width = `calc(100% - ${right}px)`;
|
||||
dom.value.style.transform = 'translateZ(0)';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
if (dom.value) {
|
||||
dom.value.style.transition = `${transformTransition},${widthTransition}`;
|
||||
dom.value.style.width = '';
|
||||
dom.value.style.transform = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const remScrollingEffect = (right: number) => {
|
||||
const { placement, duration, ease } = props;
|
||||
|
||||
dom.value.style.transition = 'none';
|
||||
let heightTransition: string;
|
||||
let widthTransition = `width ${duration} ${ease}`;
|
||||
const transformTransition = `transform ${duration} ${ease}`;
|
||||
switch (placement) {
|
||||
case 'left': {
|
||||
dom.value.style.width = '100%';
|
||||
widthTransition = `width 0s ${ease} ${duration}`;
|
||||
break;
|
||||
}
|
||||
case 'right': {
|
||||
dom.value.style.transform = `translateX(${right}px)`;
|
||||
dom.value.style.width = '100%';
|
||||
widthTransition = `width 0s ${ease} ${duration}`;
|
||||
if (maskDom.value) {
|
||||
maskDom.value.style.left = `-${right}px`;
|
||||
maskDom.value.style.width = `calc(100% + ${right}px)`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'top':
|
||||
case 'bottom': {
|
||||
dom.value.style.width = `calc(100% + ${right}px)`;
|
||||
dom.value.style.height = '100%';
|
||||
dom.value.style.transform = 'translateZ(0)';
|
||||
heightTransition = `height 0s ${ease} ${duration}`;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
if (dom.value) {
|
||||
dom.value.style.transition = `${transformTransition},${
|
||||
heightTransition ? `${heightTransition},` : ''
|
||||
}${widthTransition}`;
|
||||
dom.value.style.transform = '';
|
||||
dom.value.style.width = '';
|
||||
dom.value.style.height = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getCurrentDrawerSome = () => !Object.keys(currentDrawer).some(key => currentDrawer[key]);
|
||||
|
||||
const getLevelDom = ({ level, getContainer }) => {
|
||||
if (windowIsUndefined) {
|
||||
return;
|
||||
|
@ -426,6 +157,7 @@ const DrawerChild = defineComponent({
|
|||
canOpen.value = true;
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
const {
|
||||
width,
|
||||
|
@ -449,6 +181,11 @@ const DrawerChild = defineComponent({
|
|||
contentWrapperStyle,
|
||||
style,
|
||||
class: className,
|
||||
rootClassName,
|
||||
rootStyle,
|
||||
maskMotion,
|
||||
motion,
|
||||
inline,
|
||||
...otherProps
|
||||
} = props;
|
||||
// 首次渲染都将是关闭状态。
|
||||
|
@ -456,54 +193,53 @@ const DrawerChild = defineComponent({
|
|||
const wrapperClassName = classnames(prefixCls, {
|
||||
[`${prefixCls}-${placement}`]: true,
|
||||
[`${prefixCls}-open`]: open,
|
||||
[className]: !!className,
|
||||
[`${prefixCls}-inline`]: inline,
|
||||
'no-mask': !showMask,
|
||||
[rootClassName]: true,
|
||||
});
|
||||
|
||||
const { placementName } = horizontalBoolAndPlacementName.value;
|
||||
// 百分比与像素动画不同步,第一次打用后全用像素动画。
|
||||
// const defaultValue = !this.contentDom || !level ? '100%' : `${value}px`;
|
||||
const placementPos = placement === 'left' || placement === 'top' ? '-100%' : '100%';
|
||||
const transform = open ? '' : `${placementName}(${placementPos})`;
|
||||
|
||||
const motionProps = typeof motion === 'function' ? motion(placement) : motion;
|
||||
return (
|
||||
<div
|
||||
{...omit(otherProps, ['switchScrollingEffect', 'autofocus'])}
|
||||
tabindex={-1}
|
||||
class={wrapperClassName}
|
||||
style={style}
|
||||
style={rootStyle}
|
||||
ref={dom}
|
||||
onKeydown={open && keyboard ? onKeyDown : undefined}
|
||||
onTransitionend={onWrapperTransitionEnd}
|
||||
>
|
||||
{showMask && (
|
||||
<div
|
||||
class={`${prefixCls}-mask`}
|
||||
onClick={maskClosable ? onClose : undefined}
|
||||
style={maskStyle}
|
||||
ref={maskDom}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
class={`${prefixCls}-content-wrapper`}
|
||||
style={{
|
||||
transform,
|
||||
msTransform: transform,
|
||||
width: isNumeric(width) ? `${width}px` : width,
|
||||
height: isNumeric(height) ? `${height}px` : height,
|
||||
...contentWrapperStyle,
|
||||
}}
|
||||
ref={contentWrapper}
|
||||
<Transition {...maskMotion}>
|
||||
{showMask && (
|
||||
<div
|
||||
v-show={open}
|
||||
class={`${prefixCls}-mask`}
|
||||
onClick={maskClosable ? onClose : undefined}
|
||||
style={maskStyle}
|
||||
ref={maskDom}
|
||||
/>
|
||||
)}
|
||||
</Transition>
|
||||
<Transition
|
||||
{...motionProps}
|
||||
onAfterEnter={onAfterVisibleChange}
|
||||
onAfterLeave={onAfterVisibleChange}
|
||||
>
|
||||
<div class={`${prefixCls}-content`} ref={contentDom}>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
{slots.handler ? (
|
||||
<div onClick={onHandleClick} ref={handlerDom}>
|
||||
{slots.handler?.()}
|
||||
<div
|
||||
v-show={open}
|
||||
class={`${prefixCls}-content-wrapper`}
|
||||
style={[contentWrapperStyle]}
|
||||
ref={contentWrapper}
|
||||
>
|
||||
<div class={[`${prefixCls}-content`, className]} style={style} ref={contentDom}>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{slots.handler ? (
|
||||
<div onClick={onHandleClick} ref={handlerDom}>
|
||||
{slots.handler?.()}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -37,21 +37,28 @@ const DrawerWrapper = defineComponent({
|
|||
};
|
||||
|
||||
return () => {
|
||||
const { getContainer, wrapperClassName, forceRender, ...otherProps } = props;
|
||||
const {
|
||||
getContainer,
|
||||
wrapperClassName,
|
||||
rootClassName,
|
||||
rootStyle,
|
||||
forceRender,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
let portal = null;
|
||||
if (!getContainer) {
|
||||
return (
|
||||
<div class={wrapperClassName} ref={dom}>
|
||||
<Child
|
||||
v-slots={slots}
|
||||
{...otherProps}
|
||||
open={props.open}
|
||||
getContainer={() => dom.value}
|
||||
onClose={onClose}
|
||||
onHandleClick={onHandleClick}
|
||||
></Child>
|
||||
</div>
|
||||
<Child
|
||||
v-slots={slots}
|
||||
{...otherProps}
|
||||
rootClassName={rootClassName}
|
||||
rootStyle={rootStyle}
|
||||
open={props.open}
|
||||
onClose={onClose}
|
||||
onHandleClick={onHandleClick}
|
||||
inline={true}
|
||||
></Child>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -71,6 +78,8 @@ const DrawerWrapper = defineComponent({
|
|||
v-slots={slots}
|
||||
{...otherProps}
|
||||
{...rest}
|
||||
rootClassName={rootClassName}
|
||||
rootStyle={rootStyle}
|
||||
open={visible !== undefined ? visible : props.open}
|
||||
afterVisibleChange={
|
||||
afterClose !== undefined ? afterClose : props.afterVisibleChange
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import PropTypes from '../../_util/vue-types';
|
||||
import type { CSSProperties, PropType } from 'vue';
|
||||
import type { CSSProperties, PropType, TransitionProps } from 'vue';
|
||||
import { arrayType, objectType, functionType } from '../../_util/type';
|
||||
|
||||
export type IPlacement = 'left' | 'top' | 'right' | 'bottom';
|
||||
type ILevelMove = number | [number, number];
|
||||
|
@ -9,6 +10,8 @@ const props = () => ({
|
|||
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
style: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
class: String,
|
||||
rootClassName: String,
|
||||
rootStyle: objectType<CSSProperties>(),
|
||||
placement: {
|
||||
type: String as PropType<IPlacement>,
|
||||
},
|
||||
|
@ -26,12 +29,13 @@ const props = () => ({
|
|||
maskStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||
afterVisibleChange: Function,
|
||||
keyboard: { type: Boolean, default: undefined },
|
||||
contentWrapperStyle: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: undefined as CSSProperties,
|
||||
},
|
||||
contentWrapperStyle: arrayType<CSSProperties[]>(),
|
||||
autofocus: { type: Boolean, default: undefined },
|
||||
open: { type: Boolean, default: undefined },
|
||||
|
||||
// Motion
|
||||
motion: functionType<(placement: IPlacement) => TransitionProps>(),
|
||||
maskMotion: objectType<TransitionProps>(),
|
||||
});
|
||||
|
||||
const drawerProps = () => ({
|
||||
|
@ -51,6 +55,6 @@ const drawerChildProps = () => ({
|
|||
getOpenCount: Function as PropType<() => number>,
|
||||
scrollLocker: PropTypes.any,
|
||||
switchScrollingEffect: Function,
|
||||
inline: Boolean,
|
||||
});
|
||||
|
||||
export { drawerProps, drawerChildProps };
|
||||
|
|
Loading…
Reference in New Issue