feat(rate): basic rate

This commit is contained in:
07akioni 2020-10-23 18:01:28 +08:00
parent 92fb6928e4
commit a5f73be880
15 changed files with 265 additions and 0 deletions

View File

@ -0,0 +1,4 @@
# 基础用法
```html
<n-rate />
```

View File

@ -0,0 +1,14 @@
# 评分 Rate
## 演示
```demo
basic
```
## Props
|名称|类型|默认值|说明|
|-|-|-|-|
|count|`number`|`5`||
|value|`number`|`undefined`||
|default-value|`number`|`0`||
|on-update:value|`(value: number) => any`|`undefined`||

View File

@ -248,6 +248,12 @@ export default function (instance) {
titleExtra: 'Radio',
path: `/${lang}/${theme}/doc` + '/n-radio'
},
{
name: 'Rate',
title: '评分',
titleExtra: 'Rate',
path: `/${lang}/${theme}/doc` + '/n-rate'
},
{
name: 'Select',
title: '选择器',
@ -659,6 +665,10 @@ export default function (instance) {
name: 'Radio',
path: `/${lang}/${theme}/doc` + '/n-radio'
},
{
name: 'Rate',
path: `/${lang}/${theme}/doc` + '/n-rate'
},
{
name: 'Select',
path: `/${lang}/${theme}/doc` + '/n-select'

View File

@ -76,6 +76,7 @@ import code from '../documentation/components/code'
import upload from '../documentation/components/upload'
import table from '../documentation/components/table'
import space from '../documentation/components/space'
import rate from '../documentation/components/rate'
import Documentation from '../Documentation'
@ -156,6 +157,7 @@ export const childRoutes = withPrefix('/:lang/:theme/doc', [
{ path: '/n-upload', component: upload },
{ path: '/n-table', component: table },
{ path: '/n-space', component: space },
{ path: '/n-rate', component: rate },
// deprecated
{ path: '/n-nimbus-service-layout', component: nimbusServiceLayout }
])

View File

@ -48,6 +48,7 @@ import Popselect from './popselect'
import Popup from './popover'
import Progress from './progress'
import Radio from './radio'
import Rate from './rate'
import Result from './result'
import Select from './select'
import Scrollbar from './scrollbar'
@ -201,6 +202,8 @@ import descriptionsLightStyle from './descriptions/styles/light'
import descriptionsDarkStyle from './descriptions/styles/dark'
import formLightStyle from './form/styles/light'
import formDarkStyle from './form/styles/dark'
import rateLightStyle from './rate/styles/light'
import rateDarkStyle from './rate/styles/dark'
// Can be remove after refactoring
import baseSelectionLightStyle from './_base/selection/styles/light'
@ -294,6 +297,7 @@ export default create({
InputGroupLabelStyle,
DynamicTags,
Space,
Rate,
// Deprecated
NimbusServiceLayout,
NimbusFormCard,
@ -430,6 +434,8 @@ export default create({
formDarkStyle,
spaceDarkStyle,
spaceLightStyle,
rateDarkStyle,
rateLightStyle,
// Can be remove after refactoring
baseSelectionLightStyle,
baseSelectionDarkStyle

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

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

118
src/rate/src/Rate.vue Normal file
View File

@ -0,0 +1,118 @@
<template>
<div
class="n-rate"
:class="{
[`n-${mergedTheme}-theme`]: mergedTheme
}"
@mouseleave="handleMouseLeave(index)"
>
<div
v-for="index in count"
:key="index"
class="n-rate__item"
:class="{
'n-rate__item--active':
hoverIndex !== null
? index <= hoverIndex
: index < mergedValue
}"
@click="handleClick(index)"
@mouseenter="handleMouseEnter(index)"
>
<n-icon>
<star-icon />
</n-icon>
</div>
</div>
</template>
<script>
import {
configurable,
themeable,
usecssr,
asformitem
} from '../../_mixins'
import {
toRef,
ref
} from 'vue'
import {
useMergedState
} from 'vooks'
import {
call
} from '../../_utils'
import styles from './styles'
import StarIcon from './StarIcon.vue'
import NIcon from '../../icon'
export default {
name: 'Rate',
components: {
NIcon,
StarIcon
},
mixins: [
configurable,
themeable,
asformitem(),
usecssr(styles)
],
props: {
count: {
type: Number,
default: 5
},
value: {
type: Number,
default: undefined
},
defaultValue: {
type: Number,
default: 0
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': {
type: [Function, Array],
default: undefined
}
},
setup (props) {
const controlledValueRef = toRef(props, 'value')
const uncontrolledValueRef = ref(props.defaultValue)
return {
mergedValue: useMergedState(
controlledValueRef,
uncontrolledValueRef
),
uncontrolledValue: uncontrolledValueRef,
hoverIndex: ref(null)
}
},
methods: {
doUpdateValue (value) {
const {
'onUpdate:value': onUpdateValue,
nTriggerFormChange,
nTriggerFormInput
} = this
if (onUpdateValue) {
call(onUpdateValue, value)
}
this.uncontrolledValue = value
nTriggerFormChange()
nTriggerFormInput()
},
handleMouseEnter (index) {
this.hoverIndex = index
},
handleMouseLeave (index) {
this.hoverIndex = null
},
handleClick (index) {
this.doUpdateValue(index + 1)
}
}
}
</script>

View File

@ -0,0 +1,9 @@
<template>
<svg viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill-rule="evenodd">
<g fill-rule="nonzero">
<path d="M14.4373398,3.10348696 C14.6345524,3.20081719 14.7941799,3.36044472 14.8915102,3.55765732 L17.8153782,9.48206111 L24.353346,10.4320834 C24.8998908,10.511501 25.2785723,11.0189439 25.1991547,11.5654888 C25.1675302,11.7831258 25.065043,11.9842682 24.9075593,12.1377768 L20.1766414,16.749282 L21.2934597,23.2608319 C21.3868207,23.8051684 21.0212328,24.3221243 20.4768964,24.4154853 C20.2601388,24.4526621 20.0371707,24.4173475 19.8425102,24.3150084 L13.9947741,21.2406716 L8.14703796,24.3150084 C7.65819337,24.5720092 7.05356621,24.3840627 6.79656541,23.8952181 C6.69422634,23.7005576 6.65891166,23.4775895 6.69608851,23.2608319 L7.81290673,16.749282 L3.08198882,12.1377768 C2.68650524,11.7522756 2.67841294,11.1191623 3.06391415,10.7236788 C3.21742275,10.5661951 3.41856517,10.4637079 3.6362022,10.4320834 L10.1741699,9.48206111 L13.098038,3.55765732 C13.3424603,3.06240366 13.9420861,2.85906466 14.4373398,3.10348696 Z" />
</g>
</g>
</svg>
</template>

View File

@ -0,0 +1,11 @@
import themedBaseStyle from './themed-base.cssr.js'
export default [
{
key: 'mergedTheme',
watch: [
'mergedTheme'
],
CNode: themedBaseStyle
}
]

View File

@ -0,0 +1,51 @@
import { c, cTB, cB, cE, cM } from '../../../_utils/cssr'
export default c([
({ props }) => {
const {
itemColor,
itemColorActive
} = props.$local
const {
cubicBezierEaseInOut
} = props.$base
return cTB('rate', {
display: 'inline-flex',
flexWrap: 'no-wrap'
}, [
cE('item', {
transition: `transform .1s ${cubicBezierEaseInOut}`,
transform: 'scale(1)'
}, [
c('&:hover', {
transform: 'scale(1.05)'
}, [
cB('icon', {
transition: `
fill .1s ${cubicBezierEaseInOut},
stroke .1s ${cubicBezierEaseInOut}
`
})
]),
c('&:active', {
transform: 'scale(0.96)'
}),
c('&:not(:first-child)', {
marginLeft: '2px'
}),
cB('icon', {
fontSize: '24px',
cursor: 'pointer',
fill: itemColor,
stroke: itemColor
}),
cM('active', [
cB('icon', {
fill: itemColorActive,
stroke: itemColorActive
})
])
])
])
}
])

16
src/rate/styles/dark.js Normal file
View File

@ -0,0 +1,16 @@
import create from '../../_styles/utils/create-component-base'
import iconStyle from '../../icon/styles/dark'
export default create({
theme: 'dark',
name: 'Rate',
peer: [
iconStyle
],
getDerivedVariables ({ base, derived }) {
return {
itemColor: derived.railColor,
itemColorActive: derived.primaryColor
}
}
})

16
src/rate/styles/light.js Normal file
View File

@ -0,0 +1,16 @@
import create from '../../_styles/utils/create-component-base'
import iconStyle from '../../icon/styles/dark'
export default create({
theme: 'light',
name: 'Rate',
peer: [
iconStyle
],
getDerivedVariables ({ base, derived }) {
return {
itemColor: derived.railColor,
itemColorActive: derived.primaryColor
}
}
})