vuecssuiant-designantdreactantantd-vueenterprisefrontendui-designvue-antdvue-antd-uivue3vuecomponent
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.8 KiB
154 lines
4.8 KiB
import type { CSSProperties, PropType } from 'vue'; |
|
import { computed, ref, defineComponent, nextTick } from 'vue'; |
|
import type { MouseEventHandler } from '../_util/EventInterface'; |
|
import Transition, { getTransitionProps } from '../_util/transition'; |
|
import dialogPropTypes from './IDialogPropTypes'; |
|
import { offset } from './util'; |
|
const sentinelStyle = { width: 0, height: 0, overflow: 'hidden', outline: 'none' }; |
|
|
|
export type ContentRef = { |
|
focus: () => void; |
|
changeActive: (next: boolean) => void; |
|
}; |
|
export default defineComponent({ |
|
name: 'Content', |
|
inheritAttrs: false, |
|
props: { |
|
...dialogPropTypes(), |
|
motionName: String, |
|
ariaId: String, |
|
onVisibleChanged: Function as PropType<(visible: boolean) => void>, |
|
onMousedown: Function as PropType<MouseEventHandler>, |
|
onMouseup: Function as PropType<MouseEventHandler>, |
|
}, |
|
setup(props, { expose, slots, attrs }) { |
|
const sentinelStartRef = ref<HTMLDivElement>(); |
|
const sentinelEndRef = ref<HTMLDivElement>(); |
|
const dialogRef = ref<HTMLDivElement>(); |
|
expose({ |
|
focus: () => { |
|
sentinelStartRef.value?.focus(); |
|
}, |
|
changeActive: next => { |
|
const { activeElement } = document; |
|
if (next && activeElement === sentinelEndRef.value) { |
|
sentinelStartRef.value.focus(); |
|
} else if (!next && activeElement === sentinelStartRef.value) { |
|
sentinelEndRef.value.focus(); |
|
} |
|
}, |
|
}); |
|
const transformOrigin = ref<string>(); |
|
const contentStyleRef = computed(() => { |
|
const { width, height } = props; |
|
const contentStyle: CSSProperties = {}; |
|
if (width !== undefined) { |
|
contentStyle.width = typeof width === 'number' ? `${width}px` : width; |
|
} |
|
if (height !== undefined) { |
|
contentStyle.height = typeof height === 'number' ? `${height}px` : height; |
|
} |
|
if (transformOrigin.value) { |
|
contentStyle.transformOrigin = transformOrigin.value; |
|
} |
|
return contentStyle; |
|
}); |
|
|
|
const onPrepare = () => { |
|
nextTick(() => { |
|
if (dialogRef.value) { |
|
const elementOffset = offset(dialogRef.value); |
|
transformOrigin.value = props.mousePosition |
|
? `${props.mousePosition.x - elementOffset.left}px ${ |
|
props.mousePosition.y - elementOffset.top |
|
}px` |
|
: ''; |
|
} |
|
}); |
|
}; |
|
const onVisibleChanged = (visible: boolean) => { |
|
props.onVisibleChanged(visible); |
|
}; |
|
return () => { |
|
const { |
|
prefixCls, |
|
footer = slots.footer?.(), |
|
title = slots.title?.(), |
|
ariaId, |
|
closable, |
|
closeIcon = slots.closeIcon?.(), |
|
onClose, |
|
bodyStyle, |
|
bodyProps, |
|
onMousedown, |
|
onMouseup, |
|
visible, |
|
modalRender = slots.modalRender, |
|
destroyOnClose, |
|
motionName, |
|
} = props; |
|
let footerNode: any; |
|
if (footer) { |
|
footerNode = <div class={`${prefixCls}-footer`}>{footer}</div>; |
|
} |
|
|
|
let headerNode: any; |
|
if (title) { |
|
headerNode = ( |
|
<div class={`${prefixCls}-header`}> |
|
<div class={`${prefixCls}-title`} id={ariaId}> |
|
{title} |
|
</div> |
|
</div> |
|
); |
|
} |
|
|
|
let closer: any; |
|
if (closable) { |
|
closer = ( |
|
<button type="button" onClick={onClose} aria-label="Close" class={`${prefixCls}-close`}> |
|
{closeIcon || <span class={`${prefixCls}-close-x`} />} |
|
</button> |
|
); |
|
} |
|
|
|
const content = ( |
|
<div class={`${prefixCls}-content`}> |
|
{closer} |
|
{headerNode} |
|
<div class={`${prefixCls}-body`} style={bodyStyle} {...bodyProps}> |
|
{slots.default?.()} |
|
</div> |
|
{footerNode} |
|
</div> |
|
); |
|
const transitionProps = getTransitionProps(motionName); |
|
return ( |
|
<Transition |
|
{...transitionProps} |
|
onBeforeEnter={onPrepare} |
|
onAfterEnter={() => onVisibleChanged(true)} |
|
onAfterLeave={() => onVisibleChanged(false)} |
|
> |
|
{visible || !destroyOnClose ? ( |
|
<div |
|
{...attrs} |
|
ref={dialogRef} |
|
v-show={visible} |
|
key="dialog-element" |
|
role="document" |
|
style={[contentStyleRef.value, attrs.style]} |
|
class={[prefixCls, attrs.class]} |
|
onMousedown={onMousedown} |
|
onMouseup={onMouseup} |
|
> |
|
<div tabindex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" /> |
|
{modalRender ? modalRender({ originVNode: content }) : content} |
|
<div tabindex={0} ref={sentinelEndRef} style={sentinelStyle} aria-hidden="true" /> |
|
</div> |
|
) : null} |
|
</Transition> |
|
); |
|
}; |
|
}, |
|
});
|
|
|