mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-30 12:52:43 +08:00
refactor(button): split wave logic
This commit is contained in:
parent
682eb5fdd2
commit
75b48c7c69
2
src/_base/wave/index.js
Normal file
2
src/_base/wave/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import Wave from './src/Wave.vue'
|
||||
export default Wave
|
50
src/_base/wave/src/Wave.vue
Normal file
50
src/_base/wave/src/Wave.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div
|
||||
class="n-base-wave"
|
||||
:class="{
|
||||
'n-base-wave--active': active
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import usecssr from '../../../_mixins/usecssr'
|
||||
import styles from './styles/index.js'
|
||||
|
||||
export default {
|
||||
name: 'NBaseWave',
|
||||
mixins: [
|
||||
usecssr(styles)
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
active: false,
|
||||
animationTimerId: null
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
const animationTimerId = this.animationTimerId
|
||||
if (animationTimerId !== null) {
|
||||
window.clearTimeout(animationTimerId)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
play () {
|
||||
const animationTimerId = this.animationTimerId
|
||||
if (animationTimerId !== null) {
|
||||
window.clearTimeout(this.animationTimerId)
|
||||
this.active = false
|
||||
this.animationTimerId = null
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
void this.$el.offsetHeight
|
||||
this.active = true
|
||||
this.animationTimerId = window.setTimeout(() => {
|
||||
this.active = false
|
||||
this.animationTimerId = null
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
14
src/_base/wave/src/styles/base.cssr.js
Normal file
14
src/_base/wave/src/styles/base.cssr.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { cB, c } from '../../../../_utils/cssr/index.js'
|
||||
|
||||
export default c([
|
||||
() => cB('base-wave', {
|
||||
raw: `
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: inherit;
|
||||
`
|
||||
})
|
||||
])
|
7
src/_base/wave/src/styles/index.js
Normal file
7
src/_base/wave/src/styles/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
import baseStyle from './base.cssr.js'
|
||||
|
||||
export default [
|
||||
{
|
||||
CNode: baseStyle
|
||||
}
|
||||
]
|
@ -12,7 +12,6 @@
|
||||
'n-button--disabled': disabled,
|
||||
'n-button--loading': loading,
|
||||
'n-button--block': block,
|
||||
'n-button--rippling': rippling,
|
||||
'n-button--enter-pressed': enterPressed,
|
||||
'n-button--ghost': ghost,
|
||||
'n-button--text': text,
|
||||
@ -86,6 +85,7 @@
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<n-base-wave v-if="!text" ref="wave" />
|
||||
<div class="n-button__border-mask" />
|
||||
</button>
|
||||
</template>
|
||||
@ -98,6 +98,7 @@ import usecssr from '../../_mixins/usecssr'
|
||||
import NFadeInHeightExpandTransition from '../../_transition/FadeInHeightExpandTransition'
|
||||
import NIconSwitchTransition from '../../_transition/IconSwitchTransition'
|
||||
import NBaseLoading from '../../_base/Loading'
|
||||
import NBaseWave from '../../_base/wave'
|
||||
import NIcon from '../../Icon'
|
||||
import styles from './styles/index.js'
|
||||
// import { read, hash, createHoverColor, createActiveColor } from '../../_utils/color'
|
||||
@ -150,6 +151,7 @@ export default {
|
||||
name: 'NButton',
|
||||
components: {
|
||||
NBaseLoading,
|
||||
NBaseWave,
|
||||
NIcon,
|
||||
NIconSwitchTransition,
|
||||
NFadeInHeightExpandTransition
|
||||
@ -254,9 +256,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
enterPressed: false,
|
||||
rippling: false,
|
||||
rippleTimer: null
|
||||
enterPressed: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -335,10 +335,6 @@ export default {
|
||||
// if (colorHash) {
|
||||
// unmountColorStyle(colorHash)
|
||||
// }
|
||||
const rippleTimer = this.rippleTimer
|
||||
if (rippleTimer !== null) {
|
||||
window.clearTimeout(rippleTimer)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMouseDown (e) {
|
||||
@ -354,17 +350,10 @@ export default {
|
||||
if (!this.disabled) {
|
||||
this.$emit('click', e)
|
||||
if (!this.text) {
|
||||
window.clearTimeout(this.rippleTimer)
|
||||
this.rippleTimer = null
|
||||
this.rippling = false
|
||||
this.$nextTick().then(() => {
|
||||
void this.$el.offsetHeight
|
||||
this.rippling = true
|
||||
this.rippleTimer = window.setTimeout(() => {
|
||||
this.rippling = false
|
||||
this.rippleTimer = null
|
||||
}, 600)
|
||||
})
|
||||
const waveRef = this.$refs.wave
|
||||
if (waveRef) {
|
||||
waveRef.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -374,7 +363,7 @@ export default {
|
||||
return
|
||||
}
|
||||
this.enterPressed = false
|
||||
this.$nextTick().then(() => {
|
||||
this.$nextTick(() => {
|
||||
if (!this.disabled) {
|
||||
this.$el.click()
|
||||
}
|
||||
|
@ -1,20 +1,19 @@
|
||||
import { c, cB, cTB2, cE, cM, cNotM, namespace } from '../../../_utils/cssr'
|
||||
|
||||
const ns = namespace
|
||||
import { c, cB, cTB2, cE, cM, cNotM } from '../../../_utils/cssr'
|
||||
|
||||
function createRippleAnimation (digest, color, theme) {
|
||||
return [
|
||||
c(`@keyframes ${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-spread`, {
|
||||
c(`@keyframes ${theme}-${digest}-button-wave-spread`, {
|
||||
from: {
|
||||
boxShadow: `0 0 0 0 ${color}`
|
||||
boxShadow: `0 0 0 ${color}`
|
||||
},
|
||||
to: {
|
||||
boxShadow: `0 0 0 4px ${color}`
|
||||
// don't use exact 5px since chrome will display the animation with glitches
|
||||
boxShadow: `0 0 0.5px 4.5px ${color}`
|
||||
}
|
||||
}),
|
||||
c(`@keyframes ${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-opacity`, {
|
||||
c(`@keyframes ${theme}-${digest}-button-wave-opacity`, {
|
||||
from: {
|
||||
opacity: 0.4
|
||||
opacity: 0.6
|
||||
},
|
||||
to: {
|
||||
opacity: 0
|
||||
@ -59,6 +58,7 @@ export default c([
|
||||
const digest = instanceColor || instanceType
|
||||
const pallete = props.$local[digest]
|
||||
const theme = props.$renderedTheme
|
||||
const base = props.$base
|
||||
return [
|
||||
createRippleAnimation(
|
||||
digest,
|
||||
@ -68,162 +68,166 @@ export default c([
|
||||
cTB2(
|
||||
'button',
|
||||
[
|
||||
cM(`${digest}-colored`, [
|
||||
cM(`${digest}-colored`, createColorProps(
|
||||
pallete.textColor,
|
||||
pallete.color,
|
||||
pallete.borderColor || pallete.color
|
||||
), [
|
||||
createIconColorStyle(pallete.textColor),
|
||||
digest === 'default' ? [
|
||||
cM('tertiary-icon-depth', [
|
||||
createIconColorStyle(pallete.tertiaryDepthIconColor)
|
||||
cB('base-wave', {
|
||||
top: '-1px',
|
||||
right: '-1px',
|
||||
bottom: '-1px',
|
||||
left: '-1px',
|
||||
animationIterationCount: 1,
|
||||
animationDuration: props.$local.waveDuration,
|
||||
animationTimingFunction: `${base.easeOutCubicBezier} ${base.easeOutCubicBezier}`
|
||||
}),
|
||||
cM(`${digest}-colored`, createColorProps(
|
||||
pallete.textColor,
|
||||
pallete.color,
|
||||
pallete.borderColor || pallete.color
|
||||
), [
|
||||
// wave animation
|
||||
cB('base-wave', [
|
||||
cM('active', {
|
||||
zIndex: 1,
|
||||
animationName: `${theme}-${digest}-button-wave-spread, ${theme}-${digest}-button-wave-opacity`
|
||||
})
|
||||
]),
|
||||
// button styles
|
||||
createIconColorStyle(pallete.textColor),
|
||||
digest === 'default' ? [
|
||||
createIconColorStyle(pallete.iconColor)
|
||||
] : [],
|
||||
cNotM('disabled', [
|
||||
cM(
|
||||
'enter-pressed',
|
||||
createColorProps(
|
||||
pallete.activeTextColor || pallete.textColor,
|
||||
pallete.activeColor,
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
),
|
||||
[
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.activeTextColor || pallete.textColor)
|
||||
]
|
||||
),
|
||||
cNotM('enter-pressed', [
|
||||
c('&:hover', createColorProps(
|
||||
pallete.hoverTextColor || pallete.textColor,
|
||||
pallete.hoverColor,
|
||||
pallete.hoverBorderColor || pallete.hoverColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.hoverBorderColor || pallete.hoverColor),
|
||||
createIconColorStyle(pallete.hoverTextColor || pallete.textColor)
|
||||
]),
|
||||
c('&:active', createColorProps(
|
||||
pallete.activeTextColor || pallete.textColor,
|
||||
pallete.activeColor,
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.activeTextColor || pallete.textColor)
|
||||
])
|
||||
]),
|
||||
c('&:not(:active):focus', [
|
||||
cNotM('enter-pressed', createColorProps(
|
||||
pallete.focusTextColor || pallete.textColor,
|
||||
pallete.focusColor,
|
||||
pallete.focusBorderColor || pallete.focusColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.focusBorderColor || pallete.focusColor),
|
||||
createIconColorStyle(pallete.focusTextColor || pallete.textColor)
|
||||
])
|
||||
])
|
||||
]),
|
||||
cM(`ghost`, createColorProps(
|
||||
pallete.ghostTypedTextColor || pallete.color, 'transparent', pallete.borderColor || pallete.color
|
||||
), [
|
||||
createIconColorStyle(pallete.ghostTypedTextColor || pallete.color),
|
||||
digest === 'default' ? [
|
||||
createIconColorStyle(pallete.iconColor)
|
||||
] : [],
|
||||
cNotM('disabled', [
|
||||
cM(
|
||||
'enter-pressed',
|
||||
createColorProps(
|
||||
pallete.activeTextColor || pallete.textColor,
|
||||
pallete.activeColor,
|
||||
pallete.ghostTypedActiveTextColor || pallete.activeColor,
|
||||
'transparent',
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
),
|
||||
[
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.activeTextColor || pallete.textColor)
|
||||
createIconColorStyle(pallete.ghostTypedActiveTextColor || pallete.activeColor)
|
||||
]
|
||||
),
|
||||
cNotM('enter-pressed', [
|
||||
c('&:hover', createColorProps(
|
||||
pallete.hoverTextColor || pallete.textColor,
|
||||
pallete.hoverColor,
|
||||
pallete.ghostTypedHoverTextColor || pallete.hoverColor,
|
||||
'transparent',
|
||||
pallete.hoverBorderColor || pallete.hoverColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.hoverBorderColor || pallete.hoverColor),
|
||||
createIconColorStyle(pallete.hoverTextColor || pallete.textColor)
|
||||
createIconColorStyle(pallete.ghostTypedHoverTextColor || pallete.hoverColor)
|
||||
]),
|
||||
c('&:active', createColorProps(
|
||||
pallete.activeTextColor || pallete.textColor,
|
||||
pallete.activeColor,
|
||||
pallete.ghostTypedActiveTextColor || pallete.activeColor,
|
||||
'transparent',
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.activeTextColor || pallete.textColor)
|
||||
createIconColorStyle(pallete.ghostTypedActiveTextColor || pallete.activeColor)
|
||||
])
|
||||
]),
|
||||
c('&:not(:active):focus', [
|
||||
cNotM('enter-pressed', createColorProps(
|
||||
pallete.focusTextColor || pallete.textColor,
|
||||
pallete.focusColor,
|
||||
pallete.ghostTypedHoverTextColor || pallete.hoverColor,
|
||||
'transparent',
|
||||
pallete.focusBorderColor || pallete.focusColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.focusBorderColor || pallete.focusColor),
|
||||
createIconColorStyle(pallete.focusTextColor || pallete.textColor)
|
||||
createIconColorStyle(pallete.ghostTypedHoverTextColor || pallete.hoverColor)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
cM('text', ({
|
||||
color: pallete.textTypedTextColor || pallete.color
|
||||
}), [
|
||||
createIconColorStyle(pallete.textTypedTextColor || pallete.color),
|
||||
digest === 'default' ? [
|
||||
createIconColorStyle(pallete.iconColor)
|
||||
] : [],
|
||||
cNotM('disabled', [
|
||||
cM(
|
||||
'enter-pressed',
|
||||
createColorProps(
|
||||
pallete.textTypedActiveTextColor || pallete.activeColor,
|
||||
null,
|
||||
null
|
||||
),
|
||||
[
|
||||
createIconColorStyle(pallete.textTypedActiveTextColor || pallete.activeColor)
|
||||
]
|
||||
),
|
||||
cNotM('enter-pressed', [
|
||||
c('&:hover', createColorProps(
|
||||
pallete.textTypedHoverTextColor || pallete.hoverColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedHoverTextColor || pallete.hoverColor)
|
||||
]),
|
||||
c('&:active', createColorProps(
|
||||
pallete.textTypedActiveTextColor || pallete.activeColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedActiveTextColor || pallete.activeColor)
|
||||
])
|
||||
]),
|
||||
cM('rippling', [
|
||||
c('&::after', {
|
||||
animationName: `${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-spread, ${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-opacity`
|
||||
})
|
||||
])
|
||||
]),
|
||||
cM(`ghost`, createColorProps(
|
||||
pallete.ghostTypedTextColor || pallete.color, 'transparent', pallete.borderColor || pallete.color
|
||||
), [
|
||||
createIconColorStyle(pallete.ghostTypedTextColor || pallete.color),
|
||||
digest === 'default' ? [
|
||||
cM('tertiary-icon-depth', [
|
||||
createIconColorStyle(pallete.tertiaryDepthIconColor)
|
||||
])
|
||||
] : [],
|
||||
cNotM('disabled', [
|
||||
cM(
|
||||
'enter-pressed',
|
||||
createColorProps(
|
||||
pallete.ghostTypedActiveTextColor || pallete.activeColor,
|
||||
'transparent',
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
),
|
||||
[
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.ghostTypedActiveTextColor || pallete.activeColor)
|
||||
]
|
||||
),
|
||||
cNotM('enter-pressed', [
|
||||
c('&:hover', createColorProps(
|
||||
pallete.ghostTypedHoverTextColor || pallete.hoverColor,
|
||||
'transparent',
|
||||
pallete.hoverBorderColor || pallete.hoverColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.hoverBorderColor || pallete.hoverColor),
|
||||
createIconColorStyle(pallete.ghostTypedHoverTextColor || pallete.hoverColor)
|
||||
]),
|
||||
c('&:active', createColorProps(
|
||||
pallete.ghostTypedActiveTextColor || pallete.activeColor,
|
||||
'transparent',
|
||||
pallete.activeBorderColor || pallete.activeColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.activeBorderColor || pallete.activeColor),
|
||||
createIconColorStyle(pallete.ghostTypedActiveTextColor || pallete.activeColor)
|
||||
])
|
||||
]),
|
||||
c('&:not(:active):focus', [
|
||||
cNotM('enter-pressed', createColorProps(
|
||||
pallete.ghostTypedHoverTextColor || pallete.hoverColor,
|
||||
'transparent',
|
||||
pallete.focusBorderColor || pallete.focusColor
|
||||
), [
|
||||
createBorderMaskStyle(pallete.focusBorderColor || pallete.focusColor),
|
||||
createIconColorStyle(pallete.ghostTypedHoverTextColor || pallete.hoverColor)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
cM('text', ({
|
||||
color: pallete.textTypedTextColor || pallete.color
|
||||
}), [
|
||||
createIconColorStyle(pallete.textTypedTextColor || pallete.color),
|
||||
digest === 'default' ? [
|
||||
cM('tertiary-icon-depth', [
|
||||
createIconColorStyle(pallete.tertiaryDepthIconColor)
|
||||
])
|
||||
] : [],
|
||||
cNotM('disabled', [
|
||||
cM(
|
||||
'enter-pressed',
|
||||
createColorProps(
|
||||
pallete.textTypedActiveTextColor || pallete.activeColor,
|
||||
null,
|
||||
null
|
||||
),
|
||||
[
|
||||
createIconColorStyle(pallete.textTypedActiveTextColor || pallete.activeColor)
|
||||
]
|
||||
),
|
||||
cNotM('enter-pressed', [
|
||||
c('&:hover', createColorProps(
|
||||
pallete.textTypedHoverTextColor || pallete.hoverColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedHoverTextColor || pallete.hoverColor)
|
||||
]),
|
||||
c('&:active', createColorProps(
|
||||
pallete.textTypedActiveTextColor || pallete.activeColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedActiveTextColor || pallete.activeColor)
|
||||
])
|
||||
]),
|
||||
c('&:not(:active):focus', [
|
||||
cNotM('enter-pressed', createColorProps(
|
||||
pallete.textTypedFocusTextColor || pallete.focusColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedFocusTextColor || pallete.focusColor)
|
||||
])
|
||||
c('&:not(:active):focus', [
|
||||
cNotM('enter-pressed', createColorProps(
|
||||
pallete.textTypedFocusTextColor || pallete.focusColor,
|
||||
null,
|
||||
null
|
||||
), [
|
||||
createIconColorStyle(pallete.textTypedFocusTextColor || pallete.focusColor)
|
||||
])
|
||||
])
|
||||
])
|
||||
|
@ -28,5 +28,6 @@ export default {
|
||||
small: '18px',
|
||||
medium: '18px',
|
||||
large: '20px'
|
||||
}
|
||||
},
|
||||
waveDuration: '.6s'
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export default create({
|
||||
|
||||
rippleColor: derived.primaryColor,
|
||||
|
||||
iconColor: derived.tertiaryTextColor
|
||||
iconColor: derived.secondaryTextColor
|
||||
},
|
||||
primary: {
|
||||
color: derived.primaryColor,
|
||||
|
@ -35,7 +35,7 @@ export default create({
|
||||
|
||||
rippleColor: derived.primaryColor,
|
||||
|
||||
iconColor: derived.tertiaryTextColor
|
||||
iconColor: derived.secondaryTextColor
|
||||
},
|
||||
primary: {
|
||||
color: derived.primaryColor,
|
||||
|
Loading…
Reference in New Issue
Block a user