refactor(popconfirm): ts

This commit is contained in:
07akioni 2021-01-25 00:40:20 +08:00
parent 76fdc91e3d
commit 08549be2e4
16 changed files with 290 additions and 238 deletions

View File

@ -1,105 +0,0 @@
import { h, ref, defineComponent, provide, getCurrentInstance } from 'vue'
import { NPopover } from '../../popover'
import { omit, keep } from '../../_utils'
import { useTheme } from '../../_mixins'
import { popconfirmLight } from '../styles'
import PopconfirmPanel from './PopconfirmPanel.vue'
import style from './styles/index.cssr.js'
const panelProps = Object.keys(PopconfirmPanel.props)
export default defineComponent({
name: 'Popconfirm',
props: {
...NPopover.props,
positiveText: {
type: String,
default: undefined
},
negativeText: {
type: String,
default: undefined
},
showIcon: {
type: Boolean,
default: true
},
trigger: {
type: String,
default: 'click'
},
onPositiveClick: {
type: Function,
default: undefined
},
onNegativeClick: {
type: Function,
default: undefined
}
},
setup (props) {
const themeRef = useTheme(
'Popconfirm',
'Popconfirm',
style,
popconfirmLight,
props
)
provide('NPopconfirm', getCurrentInstance().proxy)
return {
mergedTheme: themeRef,
popoverRef: ref(null)
}
},
render () {
const { $slots: slots, $props: props, mergedTheme } = this
return h(
NPopover,
{
...omit(props, panelProps, {
unstableTheme: mergedTheme.peers.Popover,
unstableThemeOverrides: mergedTheme.overrides.Popover
}),
class: 'n-popconfirm',
ref: 'popoverRef'
},
{
trigger: slots.activator || slots.trigger,
default: () =>
h(
PopconfirmPanel,
{
...keep(props, panelProps),
onPositiveClick: () => {
const {
onPositiveClick = () => true,
'onUpdate:show': onUpdateShow
} = this
Promise.resolve(onPositiveClick()).then((value) => {
if (value === false) return
this.popoverRef.setShow(false)
onUpdateShow(false)
})
},
onNegativeClick: () => {
const {
onNegativeClick = () => true,
'onUpdate:show': onUpdateShow
} = this
Promise.resolve(onNegativeClick()).then((value) => {
if (value === false) return
this.popoverRef.setShow(false)
onUpdateShow(false)
})
}
},
{
action: slots.action,
icon: slots.icon,
default: slots.default
}
)
}
)
}
})

View File

@ -0,0 +1,114 @@
import { h, ref, defineComponent, provide, PropType, reactive } from 'vue'
import {
NPopover,
popoverProps,
PopoverRef,
PopoverTrigger
} from '../../popover'
import { omit, keep, call } from '../../_utils'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { popconfirmLight } from '../styles'
import type { PopconfirmTheme } from '../styles'
import PopconfirmPanel, { panelPropKeys } from './PopconfirmPanel'
import style from './styles/index.cssr'
import type { PopconfirmInjection } from './interface'
export default defineComponent({
name: 'Popconfirm',
props: {
...(useTheme.props as ThemeProps<PopconfirmTheme>),
...popoverProps,
positiveText: String,
negativeText: String,
showIcon: {
type: Boolean,
default: true
},
trigger: {
type: String as PropType<PopoverTrigger>,
default: 'click'
},
onPositiveClick: Function as PropType<
(e: MouseEvent) => Promise<boolean> | boolean | any
>,
onNegativeClick: Function as PropType<
(e: MouseEvent) => Promise<boolean> | boolean | any
>
},
setup (props) {
const themeRef = useTheme(
'Popconfirm',
'Popconfirm',
style,
popconfirmLight,
props
)
const popoverInstRef = ref<PopoverRef | null>(null)
function handlePositiveClick (e: MouseEvent): void {
const { onPositiveClick, 'onUpdate:show': onUpdateShow } = props
void Promise.resolve(onPositiveClick ? onPositiveClick(e) : true).then(
(value) => {
if (value === false) return
popoverInstRef.value?.setShow(false)
if (onUpdateShow) call(onUpdateShow, false)
}
)
}
function handleNegativeClick (e: MouseEvent): void {
const { onNegativeClick, 'onUpdate:show': onUpdateShow } = props
void Promise.resolve(onNegativeClick ? onNegativeClick(e) : true).then(
(value) => {
if (value === false) return
popoverInstRef.value?.setShow(false)
if (onUpdateShow) call(onUpdateShow, false)
}
)
}
provide<PopconfirmInjection>(
'NPopconfirm',
reactive({
mergedTheme: themeRef
})
)
return {
mergedTheme: themeRef,
popoverInstRef,
handlePositiveClick,
handleNegativeClick
}
},
render () {
const { $slots: slots, $props: props, mergedTheme } = this
return h(
NPopover,
{
...omit(props, panelPropKeys, {
unstableTheme: mergedTheme.peers.Popover,
unstableThemeOverrides: mergedTheme.overrides.Popover
}),
class: 'n-popconfirm',
ref: 'popoverInstRef'
},
{
trigger: slots.activator || slots.trigger,
default: () => {
const panelProps = keep(props, panelPropKeys)
return h(
PopconfirmPanel,
{
...panelProps,
onPositiveClick: this.handlePositiveClick,
onNegativeClick: this.handleNegativeClick
},
{
action: slots.action,
icon: slots.icon,
default: slots.default
}
)
}
}
)
}
})

View File

@ -0,0 +1,109 @@
import {
h,
defineComponent,
computed,
inject,
PropType,
renderSlot,
VNode,
CSSProperties
} from 'vue'
import { NButton } from '../../button'
import { NBaseIcon } from '../../_base'
import { WarningIcon } from '../../_base/icons'
import { useLocale } from '../../_mixins'
import { keysOf } from '../../_utils'
import type { PopconfirmInjection } from './interface'
export const panelProps = {
positiveText: String,
negativeText: String,
showIcon: {
type: Boolean,
default: true
},
onPositiveClick: {
type: Function as PropType<(e: MouseEvent) => void>,
required: true
},
onNegativeClick: {
type: Function as PropType<(e: MouseEvent) => void>,
required: true
}
} as const
export const panelPropKeys = keysOf(panelProps)
export default defineComponent({
name: 'NPopconfirmPanel',
props: panelProps,
setup (props) {
const { locale: localeRef } = useLocale('Popconfirm')
const NPopconfirm = inject<PopconfirmInjection>(
'NPopconfirm'
) as PopconfirmInjection
return {
...useLocale('Popconfirm'),
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { fontSize, iconSize, iconColor }
} = NPopconfirm.mergedTheme
return {
'--bezier': cubicBezierEaseInOut,
'--font-size': fontSize,
'--icon-size': iconSize,
'--icon-color': iconColor
}
}),
localizedPositiveText: computed(() => {
return props.positiveText || localeRef.value.positiveText
}),
localizedNegativeText: computed(() => {
return props.negativeText || localeRef.value.negativeText
}),
handlePositiveClick (e: MouseEvent) {
props.onPositiveClick(e)
},
handleNegativeClick (e: MouseEvent) {
props.onNegativeClick(e)
}
}
},
render () {
return (
<div style={this.cssVars as CSSProperties}>
<div class="n-popconfirm__body">
{this.showIcon ? (
<div class="n-popconfirm__icon">
<slot name="icon">
<NBaseIcon>{{ default: () => <WarningIcon /> }}</NBaseIcon>
</slot>
</div>
) : null}
{renderSlot(this.$slots, 'default')}
</div>
<div class="n-popconfirm__action">
{renderSlot(
this.$slots,
'action',
undefined,
() =>
[
<NButton size="small" onClick={this.handleNegativeClick}>
{this.localizedNegativeText}
</NButton>,
<NButton
size="small"
type="primary"
onClick={this.handlePositiveClick}
>
{this.localizedPositiveText}
</NButton>
] as VNode[]
)}
</div>
</div>
)
}
})

View File

@ -1,94 +0,0 @@
<template>
<div :style="cssVars">
<div class="n-popconfirm__body">
<div v-if="showIcon" class="n-popconfirm__icon">
<slot name="icon">
<n-base-icon>
<warning-icon />
</n-base-icon>
</slot>
</div>
<slot />
</div>
<div class="n-popconfirm__action">
<slot name="action">
<n-button size="small" @click="handleNegativeClick">
{{ localizedNegativeText }}
</n-button>
<n-button size="small" type="primary" @click="handlePositiveClick">
{{ localizedPositiveText }}
</n-button>
</slot>
</div>
</div>
</template>
<script>
import { defineComponent, computed, inject } from 'vue'
import { NButton } from '../../button'
import { NBaseIcon } from '../../_base'
import { WarningIcon } from '../../_base/icons'
import { useLocale } from '../../_mixins'
export default defineComponent({
name: 'NPopconfirmPanel',
components: {
NButton,
NBaseIcon,
WarningIcon
},
props: {
positiveText: {
type: String,
default: undefined
},
negativeText: {
type: String,
default: undefined
},
showIcon: {
type: Boolean,
default: true
},
onPositiveClick: {
type: Function,
required: true
},
onNegativeClick: {
type: Function,
required: true
}
},
setup (props) {
const { locale: localeRef } = useLocale('Popconfirm')
const NPopconfirm = inject('NPopconfirm')
return {
...useLocale('Popconfirm'),
localizedPositiveText: computed(() => {
return props.positiveText || localeRef.value.positiveText
}),
localizedNegativeText: computed(() => {
return props.negativeText || localeRef.value.negativeText
}),
handlePositiveClick () {
props.onPositiveClick()
},
handleNegativeClick () {
props.onNegativeClick()
},
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { fontSize, iconSize, iconColor }
} = NPopconfirm.mergedTheme
return {
'--bezier': cubicBezierEaseInOut,
'--font-size': fontSize,
'--icon-size': iconSize,
'--icon-color': iconColor
}
})
}
}
})
</script>

View File

@ -0,0 +1,6 @@
import type { MergedTheme } from '../../_mixins'
import type { PopconfirmTheme } from '../styles'
export interface PopconfirmInjection {
mergedTheme: MergedTheme<PopconfirmTheme>
}

View File

@ -22,7 +22,7 @@ export default cB('popconfirm', [
`)
]),
cE('action', `
margin-top: 14px;
margin-top: 8px;
display: flex;
justify-content: flex-end;
`, [

View File

@ -2,8 +2,9 @@ import { buttonDark } from '../../button/styles'
import { popoverDark } from '../../popover/styles'
import { commonDark } from '../../_styles/new-common'
import commonVars from './_common'
import type { PopconfirmTheme } from './light'
export default {
const popconfirmDark: PopconfirmTheme = {
name: 'Popconfirm',
common: commonDark,
peers: {
@ -19,3 +20,5 @@ export default {
}
}
}
export default popconfirmDark

View File

@ -1,2 +0,0 @@
export { default as popconfirmDark } from './dark.js'
export { default as popconfirmLight } from './light.js'

View File

@ -0,0 +1,3 @@
export { default as popconfirmDark } from './dark'
export { default as popconfirmLight } from './light'
export type { PopconfirmThemeVars, PopconfirmTheme } from './light'

View File

@ -1,21 +0,0 @@
import { buttonLight } from '../../button/styles'
import { popoverLight } from '../../popover/styles'
import { commonLight } from '../../_styles/new-common'
import commonVars from './_common'
export default {
name: 'Popconfirm',
common: commonLight,
peers: {
Button: buttonLight,
Popover: popoverLight
},
self (vars) {
const { fontSize, warningColor } = vars
return {
...commonVars,
fontSize,
iconColor: warningColor
}
}
}

View File

@ -0,0 +1,30 @@
import { buttonLight } from '../../button/styles'
import { popoverLight } from '../../popover/styles'
import { createTheme } from '../../_mixins'
import { commonLight, ThemeCommonVars } from '../../_styles/new-common'
import commonVars from './_common'
const self = (vars: ThemeCommonVars) => {
const { fontSize, warningColor } = vars
return {
...commonVars,
fontSize,
iconColor: warningColor
}
}
export type PopconfirmThemeVars = ReturnType<typeof self>
const popconfirmLight = createTheme({
name: 'Popconfirm',
common: commonLight,
peers: {
Button: buttonLight,
Popover: popoverLight
},
self
})
export default popconfirmLight
export type PopconfirmTheme = typeof popconfirmLight

View File

@ -1,2 +1,2 @@
export { default as NPopover, popoverProps } from './src/Popover'
export type { PopoverRef } from './src/Popover'
export type { PopoverTrigger, PopoverRef } from './src/interface'

View File

@ -13,10 +13,12 @@ import {
import { VBinder, VTarget, FollowerPlacement } from 'vueuc'
import { useMergedState, useCompitable, useIsMounted, useMemo } from 'vooks'
import { call, keep, warn } from '../../_utils'
import type { MaybeArray } from '../../_utils'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import NPopoverBody, { popoverBodyProps } from './PopoverBody'
import type { PopoverTheme } from '../styles'
import { PopoverTrigger } from './interface'
const bodyPropKeys = Object.keys(popoverBodyProps) as Array<
keyof typeof popoverBodyProps
@ -67,10 +69,6 @@ interface BodyInstance {
[key: string]: unknown
}
export interface PopoverRef {
syncPosition: () => void
}
export interface PopoverInjection {
handleMouseLeave: (e: MouseEvent) => void
handleMouseEnter: (e: MouseEvent) => void
@ -82,7 +80,6 @@ export interface PopoverInjection {
}
export const popoverProps = {
...(useTheme.props as ThemeProps<PopoverTheme>),
show: {
type: Boolean,
default: undefined
@ -96,7 +93,7 @@ export const popoverProps = {
default: true
},
trigger: {
type: String as PropType<'hover' | 'click'>,
type: String as PropType<PopoverTrigger>,
default: undefined
},
delay: {
@ -154,13 +151,14 @@ export const popoverProps = {
},
// events
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:show': {
type: Function,
default: undefined
},
'onUpdate:show': Function as PropType<
MaybeArray<(value: boolean) => void> | undefined
>,
// deprecated
onShow: {
type: Function,
type: Function as PropType<
MaybeArray<(value: boolean) => void> | undefined
>,
validator: (): boolean => {
warn(
'popover',
@ -171,7 +169,9 @@ export const popoverProps = {
default: undefined
},
onHide: {
type: Function,
type: Function as PropType<
MaybeArray<(value: boolean) => void> | undefined
>,
validator: (): boolean => {
warn(
'popover',
@ -202,7 +202,10 @@ export const popoverProps = {
export default defineComponent({
name: 'Popover',
inheritAttrs: false,
props: popoverProps,
props: {
...(useTheme.props as ThemeProps<PopoverTheme>),
...popoverProps
},
setup (props) {
const isMountedRef = useIsMounted()
// setup show

View File

@ -0,0 +1,6 @@
export type PopoverTrigger = 'click' | 'hover'
export interface PopoverRef {
syncPosition: () => void
setShow: (value: boolean) => void
}