refactor: rename Button folder to button

This commit is contained in:
07akioni 2020-06-25 17:55:11 +08:00
parent aa61e0ef92
commit 9907468ae3
16 changed files with 787 additions and 26 deletions

View File

@ -1,16 +0,0 @@
import { c, cB, cTB, cE, cM, cNotM, namespace } from '../../../_utils/cssr'
import { composite, read } from '../../../_utils/color/index'
export default c([
({ props }) => {
cB(
props.renderedTheme === props.fallbackTheme
? 'button'
: `button.${namespace}-${props.theme}-theme`,
[
props => cM(`${props.extra.value}-colored`, {}, [
])
])
}
])

View File

@ -69,7 +69,7 @@
</template>
<script>
import NIcon from '../../Icon'
import NButton from '../../Button'
import NButton from '../../button'
import iosCheckmarkCircle from '../../_icons/ios-checkmark-circle'
import mdClose from '../../_icons/md-close'
import iosHelpCircle from '../../_icons/ios-help-circle'

View File

@ -64,7 +64,7 @@ import NCheckbox from '../../../Checkbox/src/Checkbox'
import NRadioGroup from '../../../Radio/src/RadioGroup'
import NRadio from '../../../Radio/src/Radio'
import NDivider from '../../../Divider'
import NButton from '../../../Button'
import NButton from '../../../button'
import NScrollbar from '../../../Scrollbar'
import { shouldUseArrayInSingleMode } from '../utils'

View File

@ -112,7 +112,7 @@ import NBaseIcon from '../../../_base/Icon'
import uniCalendarMixin from './uniCalendarMixin'
import startOfDay from 'date-fns/startOfDay'
import NButton from '../../../Button'
import NButton from '../../../button'
const DATETIME_FORMAT = 'yyyy-MM-dd HH:mm:ss'
const DATE_FORMAT = 'yyyy-MM-dd'

View File

@ -176,7 +176,7 @@
</template>
<script>
import NButton from '../../../Button'
import NButton from '../../../button'
import NBaseIcon from '../../../_base/Icon'
import dualCalendarMixin from './dualCalendarMixin'
import startOfDay from 'date-fns/startOfDay'

View File

@ -144,7 +144,7 @@ import NBaseIcon from '../../../_base/Icon'
import uniCalendarMixin from './uniCalendarMixin'
import startOfSecond from 'date-fns/startOfSecond'
import NButton from '../../../Button'
import NButton from '../../../button'
import NTimePicker from '../../../TimePicker'
import NInput from '../../../Input'

View File

@ -262,7 +262,7 @@
</template>
<script>
import NButton from '../../../Button'
import NButton from '../../../button'
import NTimePicker from '../../../TimePicker'
import NInput from '../../../Input'
import dualCalendarMixin from './dualCalendarMixin'

View File

@ -46,7 +46,7 @@
</template>
<script>
import NButton from '../../Button'
import NButton from '../../button'
import NButtonGroup from '../../button-group'
import mdAdd from '../../_icons/md-add'
import mdRemove from '../../_icons/md-remove'

View File

@ -41,7 +41,7 @@
</template>
<script>
import NButton from '../../Button'
import NButton from '../../button'
import NIcon from '../../Icon'
import mdAlert from '../../_icons/md-alert'
import locale from '../../_mixins/locale'

View File

@ -58,7 +58,7 @@
</template>
<script>
import NButton from '../../Button'
import NButton from '../../button'
import closeOutline from '../../_icons/close-outline'
import downloadOutline from '../../_icons/download-outline'
import trashOutline from '../../_icons/trash-outline'

8
src/button/index.js Normal file
View File

@ -0,0 +1,8 @@
/* istanbul ignore file */
import Button from './src/Button.vue'
Button.install = function (Vue) {
Vue.component(Button.name, Button)
}
export default Button

393
src/button/src/Button.vue Normal file
View File

@ -0,0 +1,393 @@
<template>
<!--
color related class need to be refined, especially for it conflict with type
related class. Although it works for now, refinement is still in need. Maybe
rename type class to sth like **-info-colored is a solution in semantics.
-->
<button
class="n-button"
:class="{
'n-button--round': round,
'n-button--circle': circle,
'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,
[`n-button--${type}-type`]: true,
[`n-button--${type}-colored`]: true,
[`n-button--${syntheticSize}-size`]: true,
[`n-button--${iconPlacement}-icon`]: iconPlacement && !noTextContent,
[`n-button--${iconDepth}-icon-depth`]: type === 'default',
[`n-${syntheticTheme}-theme`]: syntheticTheme,
}"
:tabindex="syntheticFocusable ? 0 : -1"
:type="attrType"
@click="handleClick"
@blur="handleBlur"
@mousedown="handleMouseDown"
@keyup.enter="handleKeyUpEnter"
@keydown.enter="handleKeyDownEnter"
>
<div
v-if="!circle && $scopedSlots.default && iconOnRight"
class="n-button__content"
:style="{
transition: hollowOutColorTransitionDisabled ? 'none' : null,
color: hollowText ? ascendantBackgroundColor : null
}"
>
<slot />
</div>
<n-fade-in-height-expand-transition width>
<div
v-if="(hasIcon || loading)"
class="n-button__icon"
:class="{ 'n-button__icon--slot': $scopedSlots.icon }"
>
<n-icon-switch-transition>
<n-base-loading
v-if="loading"
key="loading"
class="n-icon-slot"
:theme="syntheticTheme"
:style="{
transition: hollowOutColorTransitionDisabled ? 'none' : null
}"
:stroke="hollowText ? ascendantBackgroundColor : null"
:stroke-width="24"
/>
<n-icon
v-else
key="icon"
:style="{
transition: hollowOutColorTransitionDisabled ? 'none' : null,
fill: hollowText ? ascendantBackgroundColor : null,
stroke: hollowText ? ascendantBackgroundColor : null
}"
class="n-icon-slot"
>
<slot
name="icon"
/>
</n-icon>
</n-icon-switch-transition>
</div>
</n-fade-in-height-expand-transition>
<div
v-if="!circle && $scopedSlots.default && !iconOnRight"
class="n-button__content"
:style="{
transition: hollowOutColorTransitionDisabled ? 'none' : null,
color: hollowText ? ascendantBackgroundColor : null
}"
>
<slot />
</div>
<div class="n-button__border-mask" />
</button>
</template>
<script>
import NBaseLoading from '../../_base/Loading'
import NFadeInHeightExpandTransition from '../../_transition/FadeInHeightExpandTransition'
import hollowoutable from '../../_mixins/hollowoutable'
import withapp from '../../_mixins/withapp'
import themeable from '../../_mixins/themeable'
import usecssr from '../../_mixins/usecssr'
import NIcon from '../../Icon'
import NIconSwitchTransition from '../../_transition/IconSwitchTransition'
import styles from './styles/index.js'
// import { read, hash, createHoverColor, createActiveColor } from '../../_utils/color'
// import { createColorStyle } from './styles/Button.cssr.js'
// import { createThemedStyle } from '../../_utils/cssr'
// import createTheme from './styles/theme'
// const colorStyle = createColorStyle()
// let typeStyle
// function mountTypeStyle (type) {
// typeStyle.mount({
// target: 'n-button-' + type + '-style',
// props: {
// type
// }
// })
// }
// function mountColorStyle (color, colorHash) {
// const textColor = null
// const rgb = read(color)
// const digest = hash(rgb)
// const hoverColor = createHoverColor(rgb)
// const activeColor = createActiveColor(rgb)
// const focusColor = hoverColor
// colorStyle.mount({
// target: 'n-button-' + digest,
// props: {
// digest,
// pallete: {
// color,
// hoverColor,
// activeColor,
// focusColor,
// textColor
// }
// }
// })
// }
// function unmountColorStyle (colorHash) {
// colorStyle.unmount({
// target: 'n-button-' + colorHash,
// delay: 3000
// })
// }
export default {
name: 'NButton',
components: {
NBaseLoading,
NIcon,
NIconSwitchTransition,
NFadeInHeightExpandTransition
},
inject: {
NButtonGroup: {
default: null
},
NFormItem: {
default: null
}
},
mixins: [
withapp,
themeable,
hollowoutable,
usecssr(styles)
],
props: {
color: {
type: String,
default: null
},
text: {
type: Boolean,
default: false
},
block: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
size: {
validator (value) {
return ['tiny', 'small', 'medium', 'large'].includes(value)
},
default: 'medium'
},
ghost: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
focusable: {
type: Boolean,
default: true
},
keyboard: {
type: Boolean,
default: true
},
type: {
// TODO: warning message
validator (value) {
return [
'default',
'primary',
'info',
'success',
'warning',
'error'
].includes(value)
},
default: 'default'
},
icon: {
type: String,
default: null
},
iconPlacement: {
default: 'left',
validator (value) {
return ['left', 'right'].includes(value)
}
},
iconDepth: {
default: 'secondary',
validator (value) {
return ['secondary', 'tertiary'].includes(value)
}
},
attrType: {
default: 'button',
validator (value) {
return ['button', 'submit', 'reset'].includes(value)
}
}
},
data () {
return {
enterPressed: false,
rippling: false,
rippleTimer: null
}
},
computed: {
// colorRgb () {
// if (!this.color) return null
// return read(this.color)
// },
// colorHash () {
// if (!this.colorRgb) return null
// return hash(this.colorRgb)
// },
syntheticSize () {
const NButtonGroup = this.NButtonGroup
if (NButtonGroup && NButtonGroup.size) {
return NButtonGroup.size
}
const NFormItem = this.NFormItem
if (
NFormItem &&
NFormItem !== '__FORM_ITEM_INNER__' &&
NFormItem.syntheticSize
) {
return NFormItem.syntheticSize
}
return this.size
},
noTextContent () {
return this.circle || !this.$scopedSlots.default
},
avoidHollowOut () {
return (
this.text ||
this.ghost ||
(this.type === 'default' && !this.color)
)
},
hollowText () {
return !this.avoidHollowOut
},
syntheticFocusable () {
return this.focusable && !this.disabled
},
hasIcon () {
return this.icon || this.$scopedSlots.icon
},
iconOnRight () {
return this.iconPlacement === 'right'
}
},
// watch: {
// colorHash (value, oldValue) {
// unmountColorStyle(oldValue)
// },
// color (value) {
// mountColorStyle(value)
// },
// type (value) {
// mountTypeStyle(value)
// }
// },
created () {
// const color = this.color
// if (color) {
// mountColorStyle(color)
// }
// if (!typeStyle) {
// typeStyle = createThemedStyle(colorStyle, createTheme(
// this.$naive.styleSchemes,
// this.$naive.fallbackTheme
// ))
// }
// mountTypeStyle(this.type)
},
beforeDestroy () {
// const colorHash = this.colorHash
// if (colorHash) {
// unmountColorStyle(colorHash)
// }
const rippleTimer = this.rippleTimer
if (rippleTimer !== null) {
window.clearTimeout(rippleTimer)
}
},
methods: {
handleMouseDown (e) {
e.preventDefault()
if (this.disabled) {
return
}
if (this.syntheticFocusable) {
this.$el.focus()
}
},
handleClick (e) {
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)
})
}
}
},
handleKeyUpEnter (e) {
if (!this.keyboard) {
e.preventDefault()
return
}
this.enterPressed = false
this.$nextTick().then(() => {
if (!this.disabled) {
this.$el.click()
}
})
},
handleKeyDownEnter (e) {
e.preventDefault()
if (!this.keyboard) return
this.enterPressed = true
},
handleBlur (e) {
this.enterPressed = false
}
}
}
</script>

View File

@ -0,0 +1,241 @@
import { c, cB, cE, cM, cNotM, namespace } from '../../../_utils/cssr'
const ns = namespace
function createRippleAnimation (digest, color, theme) {
return [
c(`@keyframes ${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-spread`, {
from: {
boxShadow: `0 0 0 0 ${color}`
},
to: {
boxShadow: `0 0 0 4px ${color}`
}
}),
c(`@keyframes ${ns}-${theme ? theme + '-' : ''}button-${digest}-colored-ripple-opacity`, {
from: {
opacity: 0.4
},
to: {
opacity: 0
}
})
]
}
function createColorProps (
color, backgroundColor, borderColor
) {
const props = {}
if (color) props.color = color
if (backgroundColor) props.backgroundColor = backgroundColor
if (borderColor) props.border = `1px solid ${borderColor}`
return props
}
function createIconColorStyle (iconColor) {
return cE('icon', [
cB('icon', {
fill: iconColor,
stroke: iconColor
}),
cB('base-loading', {
fill: iconColor,
stroke: iconColor
})
])
}
function createBorderMaskStyle (color) {
return cE('border-mask', {
boxShadow: `inset 0 0 0 1px ${color}`
})
}
export default c([
({ props }) => {
const instanceColor = props.$instance.color
const instanceType = props.$instance.type
const digest = instanceColor || instanceType
const pallete = props[digest]
const theme = props.$renderedTheme
return [
createRippleAnimation(
digest,
pallete.rippleColor || pallete.borderColor || pallete.color,
theme
),
cB(
'button',
[
c(
theme === props.$fallbackTheme ? '' : `&.${namespace}-${theme}-theme`,
[
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)
])
] : [],
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('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)
])
])
])
])
])
])
]
)
]
)
]
}
])

View File

@ -0,0 +1,34 @@
import colorStyle from './color.cssr.js'
import sizeStyle from './size.cssr.js'
// import typeStyle from './type.cssr.js'
// import syntheticThemeStyle from './syntheticTheme.cssr.js'
export default [
{
key: 'type',
CNode: colorStyle,
watch: [
'type',
'syntheticTheme'
]
},
{
key: 'size',
CNode: sizeStyle,
watch: [
'size'
]
}
// {
// key: 'color',
// CNode: colorStyle,
// watch: [
// 'color'
// ]
// }
// syntheticTheme: [
// {
// CNode: colorStyle
// }
// ]
]

View File

@ -0,0 +1,101 @@
import { c, cB, cE, cM, cNotM, namespace } from '../../../_utils/cssr'
import formatLength from '../../../_utils/css/formatLength'
export default c([
({ props }) => {
const theme = props.$renderedTheme
const size = props.$instance.size
const height = props.height[size]
const fontSize = props.fontSize[size]
const borderRadius = props.borderRadius
const padding = props.padding[size]
const roundPadding = props.roundPadding[size]
const roundBorderRadius = formatLength(height, 0.5)
const lineHeight = formatLength(height, 1, -2)
const iconSize = props.iconSize[size]
return cB(
'button',
[
c(
theme === props.$fallbackTheme ? '' : `&.${namespace}-${theme}-theme`,
[
cM(`${size}-size`, {
borderRadius,
fontSize,
whiteSpace: 'nowrap'
}, [
cNotM('text', {
height,
lineHeight: lineHeight,
padding
}),
cM('round', {
padding: roundPadding,
borderRadius: roundBorderRadius
}),
cM('circle', {
borderRadius: roundBorderRadius,
width: height,
padding: '0 !important'
}),
cM('text', {
padding: 0,
borderRadius: 0
}, [
cE('icon', {
height: iconSize,
lineHeight: iconSize
})
]),
cE('content', {
display: 'inline-block',
lineHeight: 'inherit'
}),
cE('icon', {
display: 'inline-block',
position: 'relative',
lineHeight,
height: lineHeight,
width: iconSize,
maxWidth: iconSize,
verticalAlign: 'bottom'
}, [
cB('icon', {
fontSize: iconSize
}),
cB('base-loading', {
height: formatLength(iconSize, 1, -2),
width: formatLength(iconSize, 1, -2),
position: 'absolute',
left: 0,
top: '50%',
transform: 'translateY(-50%)',
display: 'block'
// icon switch transition
}),
cM('slot', {
width: iconSize,
fontSize: iconSize,
display: 'inline-flex',
alignItems: 'center',
verticalAlign: 'bottom'
}, [
cB('icon-slot', {
position: 'absolute',
left: 0,
top: '50%',
transform: 'translateY(-50%)',
display: 'block',
lineHeight: iconSize,
height: iconSize,
fontSize: iconSize
})
])
])
])
]
)
]
)
}
])

View File

@ -4,7 +4,7 @@ import GradientText from './GradientText'
import Table from './Table'
import DataTable from './DataTable'
import CheckBox from './Checkbox'
import Button from './Button'
import Button from './button'
import ButtonGroup from './button-group'
import Switch from './Switch'
import Select from './Select'