import { debounce } from '@opentiny/utils'
import { addClass, removeClass } from '@opentiny/utils'
import type { IDrawerState, IDrawerApi, IDrawerCT, ISharedRenderlessParamUtils, IDrawerRenderlessParams } from '@/types'
export const watchToggle =
({ emit }: Pick<IDrawerRenderlessParams, 'emit'>) =>
(bool: boolean) => {
setTimeout(() => {
emit('update:visible', bool)
}, 200)
}
export const computedWidth =
({
state,
designConfig,
props,
constants
}: Pick<IDrawerRenderlessParams, 'state' | 'designConfig' | 'props' | 'constants'>) =>
(): string => {
if (state.width) {
return state.width + 'px'
}
return props.width || designConfig?.constants?.DEFAULT_WIDTH || (constants as IDrawerCT).DEFAULT_WIDTH
}
export const computedHeight =
({
state,
designConfig,
props,
constants
}: Pick<IDrawerRenderlessParams, 'state' | 'designConfig' | 'props' | 'constants'>) =>
(): string => {
if (state.height) {
return state.height + 'px'
}
return props.height || designConfig?.constants?.DEFAULT_HEIGHT || (constants as IDrawerCT).DEFAULT_HEIGHT
}
export const close =
({ api }: { api: IDrawerApi }) =>
(force = true) => {
api.handleClose('close', typeof force === 'boolean' ? force : false)
}
export const closed =
({ state, emit }: Pick<IDrawerRenderlessParams, 'state' | 'emit'>) =>
() => {
if (!state.visible) {
emit('closed')
}
}
export const watchVisible =
({ state, props, parent, api }: Pick<IDrawerRenderlessParams, 'state' | 'props' | 'parent' | 'api'>) =>
(value: boolean) => {
value ? api.open() : api.close()
setTimeout(() => {
state.toggle = value
}, 0)
if (value) {
const el = parent.$el
if (props.appendToBody && el && el.parentNode !== document.body) {
document.body.appendChild(el)
}
}
}
export const open =
({ state, emit, vm }: Pick<IDrawerRenderlessParams, 'state' | 'emit' | 'vm'>) =>
() => {
if (!state.visible) {
setTimeout(() => {
state.visible = true
emit('open', vm)
emit('update:visible', true)
}, 0)
}
}
export const confirm =
({ api }: { api: IDrawerApi }) =>
() => {
api.handleClose('confirm')
}
export const handleClose =
({ emit, props, state }: Pick<IDrawerRenderlessParams, 'emit' | 'props' | 'state'>) =>
(type: string, force?: boolean) => {
const isMaskNotClosable = type === 'mask' && !props.maskClosable
const isBlockClose = !force && typeof props.beforeClose === 'function' && props.beforeClose(type) === false
if (isMaskNotClosable || isBlockClose) {
return
}
state.toggle = false
if (state.visible) {
state.visible = false
setTimeout(() => {
emit('update:visible', false)
emit(['close', 'confirm'].includes(type) ? type : 'close')
}, 200)
}
}
export const keydown =
({ api, state, props }: Pick<IDrawerRenderlessParams, 'api' | 'state' | 'props'>) =>
(event: KeyboardEvent) => {
if (!state.visible) {
return
}
if (!props.closeOnPressEscape) {
return
}
if (event.key === 'Escape' || event.key === 'Esc') {
api.handleClose('esc', true)
}
}
export const addKeydownEvent =
({ api }: { api: IDrawerApi }) =>
() => {
document.addEventListener('keydown', api.keydown)
}
export const removeKeydownEvent =
({ api }: { api: IDrawerApi }) =>
() => {
document.removeEventListener('keydown', api.keydown)
}
export const mousedown =
({ state, vm }: { vm: ISharedRenderlessParamUtils<IDrawerCT>['vm']; state: IDrawerState }) =>
(event) => {
event.preventDefault()
const touch = event.touches ? event.touches[0] : event
const drawerBox = vm.$refs.drawerBox
state.dragEvent.isDrag = true
state.dragEvent.x = touch.clientX
state.dragEvent.y = touch.clientY
state.dragEvent.offsetWidth = drawerBox.offsetWidth
state.dragEvent.offsetHeight = drawerBox.offsetHeight
}
export const mousemove = ({ state, props, emit }: Pick<IDrawerRenderlessParams, 'state' | 'props' | 'emit'>) =>
debounce(1, (event) => {
if (!state.dragEvent.isDrag) {
return
}
event.preventDefault()
const { placement } = props
const {
dragEvent: { x, y, offsetWidth, offsetHeight }
} = state
const { touches, targetTouches, changedTouches } = event
const touch =
(touches && touches[0]) || (targetTouches && targetTouches[0]) || (changedTouches && changedTouches[0])
const { clientX, clientY } = touch || event
const offsetX = clientX - x
const offsetY = clientY - y
if (placement === 'left') {
state.width = offsetWidth + offsetX
} else if (placement === 'right') {
state.width = offsetWidth - offsetX
} else if (placement === 'top') {
const height = offsetHeight + offsetY
state.height = height > 10 ? height : 10
} else if (placement === 'bottom') {
const height = offsetHeight - offsetY
state.height = height > 10 ? height : 10
}
emit('drag', { width: state.width, height: state.height })
}) as Parameters<Document['removeEventListener']>['1']
export const mouseup =
({ state }: { state: IDrawerState }) =>
(event: MouseEvent) => {
if (!state.dragEvent.isDrag) {
return
}
event.preventDefault()
state.dragEvent.isDrag = false
}
export const addDragEvent =
({ api, vm }: { api: IDrawerApi; vm: ISharedRenderlessParamUtils<IDrawerCT>['vm'] }) =>
() => {
const el = vm.$refs.dragBar
el.addEventListener('mousedown', api.mousedown)
document.addEventListener('mousemove', api.mousemove)
document.addEventListener('mouseup', api.mouseup)
el.addEventListener('touchstart', api.mousedown)
el.addEventListener('touchmove', api.mousemove)
el.addEventListener('touchend', api.mouseup)
}
export const removeDragEvent =
({ api, vm }: { api: IDrawerApi; vm: ISharedRenderlessParamUtils<IDrawerCT>['vm'] }) =>
() => {
const el = vm.$refs.dragBar
el.removeEventListener('mousedown', api.mousedown)
document.removeEventListener('mousemove', api.mousemove)
document.removeEventListener('mouseup', api.mouseup)
el.removeEventListener('touchstart', api.mousedown)
el.removeEventListener('touchmove', api.mousemove)
el.removeEventListener('touchend', api.mouseup)
}
export const showScrollbar = (lockScrollClass: string) => () => {
addClass(document.body, lockScrollClass)
}
export const hideScrollbar = (lockScrollClass: string) => () => {
removeClass(document.body, lockScrollClass)
}