feat(radio): css in js (#279)

This commit is contained in:
Wanli Song 2020-08-27 11:17:28 +08:00 committed by 07akioni
parent c563838d95
commit c98cf20a75
22 changed files with 646 additions and 47 deletions

View File

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

View File

@ -9,6 +9,7 @@
@import './BaseTrackingRect.scss'; @import './BaseTrackingRect.scss';
@import './DatePicker.scss'; @import './DatePicker.scss';
@import './Descriptions.scss'; @import './Descriptions.scss';
// @import './Radio.scss';
@import './Form.scss'; @import './Form.scss';
@import './Grid.scss'; @import './Grid.scss';
@import './Layout.scss'; @import './Layout.scss';

View File

@ -64,7 +64,7 @@
<script> <script>
import NCheckbox from '../../checkbox' import NCheckbox from '../../checkbox'
import NRadio from '../../Radio' import NRadio from '../../radio'
import NBaseLoading from '../../_base/loading' import NBaseLoading from '../../_base/loading'
export default { export default {

View File

@ -61,8 +61,8 @@
<script> <script>
import NCheckboxGroup from '../../../checkbox/src/CheckboxGroup' import NCheckboxGroup from '../../../checkbox/src/CheckboxGroup'
import NCheckbox from '../../../checkbox/src/Checkbox' import NCheckbox from '../../../checkbox/src/Checkbox'
import NRadioGroup from '../../../Radio/src/RadioGroup' import NRadioGroup from '../../../radio/src/RadioGroup'
import NRadio from '../../../Radio/src/Radio' import NRadio from '../../../radio/src/Radio'
import NDivider from '../../../divider' import NDivider from '../../../divider'
import NButton from '../../../button' import NButton from '../../../button'
import NScrollbar from '../../../scrollbar' import NScrollbar from '../../../scrollbar'

View File

@ -47,7 +47,7 @@ import Popconfirm from './popconfirm'
import Popselect from './popselect' import Popselect from './popselect'
import Popup from './Popover' import Popup from './Popover'
import Progress from './progress' import Progress from './progress'
import Radio from './Radio' import Radio from './radio'
import Result from './result' import Result from './result'
import Select from './select' import Select from './select'
import Scrollbar from './scrollbar' import Scrollbar from './scrollbar'
@ -168,6 +168,8 @@ import thingLightStyle from './thing/styles/light'
import thingDarkStyle from './thing/styles/dark' import thingDarkStyle from './thing/styles/dark'
import switchLightStyle from './switch/styles/light' import switchLightStyle from './switch/styles/light'
import switchDarkStyle from './switch/styles/dark' import switchDarkStyle from './switch/styles/dark'
import radioLightStyle from './radio/styles/light'
import radioDarkStyle from './radio/styles/dark'
// Can be remove after refactoring // Can be remove after refactoring
import baseSelectionLightStyle from './_base/selection/styles/light' import baseSelectionLightStyle from './_base/selection/styles/light'
@ -365,6 +367,8 @@ export default create({
thingDarkStyle, thingDarkStyle,
switchLightStyle, switchLightStyle,
switchDarkStyle, switchDarkStyle,
radioLightStyle,
radioDarkStyle,
// Can be remove after refactoring // Can be remove after refactoring
baseSelectionLightStyle, baseSelectionLightStyle,
baseSelectionDarkStyle baseSelectionDarkStyle

12
src/radio/index.js Normal file
View File

@ -0,0 +1,12 @@
/* istanbul ignore file */
import Radio from './src/Radio.vue'
import RadioGroup from './src/RadioGroup.vue'
import RadioButton from './src/RadioButton.vue'
Radio.install = function (Vue, naive) {
Vue.component(naive.componentPrefix + Radio.name, Radio)
Vue.component(naive.componentPrefix + RadioGroup.name, RadioGroup)
Vue.component(naive.componentPrefix + RadioButton.name, RadioButton)
}
export default Radio

View File

@ -40,34 +40,40 @@ import asformitem from '../../_mixins/asformitem'
import withapp from '../../_mixins/withapp' import withapp from '../../_mixins/withapp'
import themeable from '../../_mixins/themeable' import themeable from '../../_mixins/themeable'
import radioMixin from './radioMixin' import radioMixin from './radioMixin'
import usecssr from '../../_mixins/usecssr'
import styles from './styles/radio/index.js'
export default { export default {
name: 'NRadio', name: 'Radio',
mixins: [ withapp, themeable, asformitem( mixins: [
{ withapp,
change: 'change', themeable,
blur: 'blur', usecssr(styles),
focus: 'focus' asformitem(
}, {
'medium', change: 'change',
function () { blur: 'blur',
const size = this.size focus: 'focus'
if (size) return size },
const NRadioGroup = this.NRadioGroup 'medium',
if (NRadioGroup && NRadioGroup.syntheticSize) { function () {
return NRadioGroup.syntheticSize const size = this.size
} if (size) return size
const NFormItem = this.NFormItem const NRadioGroup = this.NRadioGroup
if ( if (NRadioGroup && NRadioGroup.syntheticSize) {
NFormItem && return NRadioGroup.syntheticSize
}
const NFormItem = this.NFormItem
if (
NFormItem &&
NFormItem !== '__FORM_ITEM_INNER__' && NFormItem !== '__FORM_ITEM_INNER__' &&
NFormItem.syntheticSize NFormItem.syntheticSize
) { ) {
return NFormItem.syntheticSize return NFormItem.syntheticSize
}
return 'medium'
} }
return 'medium' ), radioMixin ],
}
), radioMixin ],
props: { props: {
size: { size: {
validator (value) { validator (value) {

View File

@ -31,10 +31,17 @@
<script> <script>
import radioMixin from './radioMixin' import radioMixin from './radioMixin'
import usecssr from '../../_mixins/usecssr'
import styles from './styles/radio-button/index.js'
export default { export default {
name: 'NRadioButton', name: 'RadioButton',
mixins: [ radioMixin ], cssrName: 'Radio',
cssrId: 'RadioButton',
mixins: [
radioMixin,
usecssr(styles)
],
created () { created () {
this.NRadioGroup && this.NRadioGroup.radioButtonCount++ this.NRadioGroup && this.NRadioGroup.radioButtonCount++
}, },

View File

@ -4,6 +4,8 @@ import themeable from '../../_mixins/themeable'
import hollowoutable from '../../_mixins/hollowoutable' import hollowoutable from '../../_mixins/hollowoutable'
import asformitem from '../../_mixins/asformitem' import asformitem from '../../_mixins/asformitem'
import getDefaultSlot from '../../_utils/vue/getDefaultSlot' import getDefaultSlot from '../../_utils/vue/getDefaultSlot'
import usecssr from '../../_mixins/usecssr'
import styles from './styles/radio-group/index.js'
function mapSlot (h, defaultSlot, groupInstance) { function mapSlot (h, defaultSlot, groupInstance) {
const mappedSlot = [] const mappedSlot = []
@ -14,14 +16,14 @@ function mapSlot (h, defaultSlot, groupInstance) {
const instanceCtorOptions = instanceOptions && instanceOptions.Ctor.options const instanceCtorOptions = instanceOptions && instanceOptions.Ctor.options
if ( if (
!instanceOptions || !instanceOptions ||
!['NRadio', 'NRadioButton'].includes(instanceCtorOptions.name) !['Radio', 'RadioButton'].includes(instanceCtorOptions.name)
) { ) {
console.error( console.error(
'[naive ui/radio]: `n-radio-group` only taks `n-radio` and `n-radio-button` as children.' '[naive ui/radio]: `n-radio-group` only taks `n-radio` and `n-radio-button` as children.'
) )
continue continue
} }
if (i === 0 || instanceCtorOptions.name === 'NRadio') { if (i === 0 || instanceCtorOptions.name === 'Radio') {
mappedSlot.push(wrappedInstance) mappedSlot.push(wrappedInstance)
} else { } else {
const lastInstanceComponentOptions = mappedSlot[mappedSlot.length - 1].componentOptions const lastInstanceComponentOptions = mappedSlot[mappedSlot.length - 1].componentOptions
@ -73,10 +75,18 @@ function mapSlot (h, defaultSlot, groupInstance) {
} }
export default { export default {
name: 'NRadioGroup', name: 'RadioGroup',
mixins: [withapp, themeable, hollowoutable, asformitem({ cssrName: 'Radio',
change: 'change' cssrId: 'RadioGroup',
}, 'small')], mixins: [
withapp,
themeable,
usecssr(styles),
hollowoutable,
asformitem({
change: 'change'
}, 'small')
],
model: { model: {
prop: 'value', prop: 'value',
event: 'change' event: 'change'

View File

@ -0,0 +1,19 @@
import sizeStyle from './themed-size.cssr.js'
import baseStyle from './themed-base.cssr.js'
export default [
{
key: 'syntheticSize',
watch: [
'syntheticSize'
],
CNode: sizeStyle
},
{
key: 'syntheticTheme',
watch: [
'syntheticTheme'
],
CNode: baseStyle
}
]

View File

@ -0,0 +1,141 @@
import { c, cTB, cB, cE, cM, cNotM } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const {
buttonBorderColorDefault,
buttonBorderColorActive,
buttonBackgroundColorActive,
buttonLabelColorDefault,
buttonLabelColorActive,
buttonLabelColorHover,
disabledOpacity,
borderMaskWidth,
buttonBoxShadowFocus,
buttonBoxShadowHover,
buttonBorderRadius
} = props.$local
const {
easeInOutCubicBezier
} = props.$base
return cTB('radio-group', [
cM('button-group', {
raw: `
white-space: nowrap;
height: 28px;
line-height: 28px;
`
}),
cM('transition-disabled', [
cB('radio-button', {
raw: `
transition: none !important;
`
})
]),
cB('radio-button', {
raw: `
vertical-align: bottom;
outline: none;
position: relative;
user-select: none;
display: inline-block;
height: 28px;
line-height: 28px;
box-sizing: border-box;
padding-left: 14px;
padding-right: 14px;
white-space: nowrap;
transition: background-color .3s ${easeInOutCubicBezier}, opacity .3s ${easeInOutCubicBezier}, border-color .3s ${easeInOutCubicBezier}, color .3s ${easeInOutCubicBezier};
`,
color: buttonLabelColorDefault,
borderTop: `1px solid ${buttonBorderColorDefault}`,
borderBottom: `1px solid ${buttonBorderColorDefault}`
}, [
cE('radio-input', {
raw: `
width: 0;
height: 0;
opacity: 0;
margin: 0;
`
}),
cE('border-mask', {
raw: `
pointer-events: none;
position: absolute;
box-shadow: inset 0 0 0 ${borderMaskWidth} transparent;
transition: box-shadow .3s ${easeInOutCubicBezier};
left: -1px;
bottom: -1px;
right: -1px;
top: -1px;
`
}),
c('&:first-child', {
raw: `
border-top-left-radius: ${buttonBorderRadius};
border-bottom-left-radius: ${buttonBorderRadius};
`,
borderLeft: `1px solid ${buttonBorderColorDefault}`
}, [
cE('border-mask', {
raw: `
border-top-left-radius: ${buttonBorderRadius};
border-bottom-left-radius: ${buttonBorderRadius};
`
})
]),
c('&:last-child', {
raw: `
border-top-right-radius: ${buttonBorderRadius};
border-bottom-right-radius: ${buttonBorderRadius};
`,
borderRight: `1px solid ${buttonBorderColorDefault}`
}, [
cE('border-mask', {
raw: `
border-top-right-radius: ${buttonBorderRadius};
border-bottom-right-radius: ${buttonBorderRadius};
`
})
]),
cNotM('disabled', {
raw: `
cursor: pointer;
`
}, [
c('&:hover', [
cE('border-mask', {
raw: `
transition: box-shadow .3s ${easeInOutCubicBezier};
`,
boxShadow: buttonBoxShadowHover
}),
cNotM('checked', {
color: buttonLabelColorHover
})
]),
cM('focus', [
c('&:not(:active)', [
cE('border-mask', {
boxShadow: buttonBoxShadowFocus
})
])
])
]),
cM('checked', {
backgroundColor: buttonBackgroundColorActive,
color: buttonLabelColorActive,
borderColor: buttonBorderColorActive
}),
cM('disabled', {
raw: `
cursor: not-allowed;
`,
opacity: disabledOpacity
})
])
])
}
])

View File

@ -0,0 +1,25 @@
import { c, cB, cM } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const size = props.$instance.syntheticSize
const height = props.$local.height[size]
const fontSize = props.$local.fontSize[size]
return cB(
'radio-group',
[
cM(`${size}-size`, [
cM('button-group', {
lineHeight: height,
height
}),
cM('radio-button', {
lineHeight: height,
height,
fontSize
})
])
]
)
}
])

View File

@ -0,0 +1,19 @@
import sizeStyle from './themed-size.cssr.js'
import baseStyle from './themed-base.cssr.js'
export default [
{
key: 'syntheticSize',
watch: [
'syntheticSize'
],
CNode: sizeStyle
},
{
key: 'syntheticTheme',
watch: [
'syntheticTheme'
],
CNode: baseStyle
}
]

View File

@ -0,0 +1,37 @@
import { c, cTB, cE, cM } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const {
buttonBorderColorDefault,
buttonBorderColorActive,
disabledOpacity
} = props.$local
const {
easeInOutCubicBezier
} = props.$base
return cTB('radio-group', {
raw: `
display: inline-block;
`
}, [
cE('splitor', {
raw: `
display: inline-block;
vertical-align: bottom;
height: 28px;
width: 1px;
transition: background-color .3s ${easeInOutCubicBezier}, opacity .3s ${easeInOutCubicBezier};
`,
backgroundColor: buttonBorderColorDefault
}, [
cM('checked', {
backgroundColor: buttonBorderColorActive
}),
cM('disabled', {
opacity: disabledOpacity
})
])
])
}
])

View File

@ -0,0 +1,18 @@
import { c, cB, cM } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const size = props.$instance.syntheticSize
const height = props.$local.height[size]
return cB(
'radio-group',
[
cM(`${size}-size`, [
cM('splitor', {
height
})
])
]
)
}
])

View File

@ -0,0 +1,19 @@
import sizeStyle from './themed-size.cssr.js'
import baseStyle from './themed-base.cssr.js'
export default [
{
key: 'syntheticSize',
watch: [
'syntheticSize'
],
CNode: sizeStyle
},
{
key: 'syntheticTheme',
watch: [
'syntheticTheme'
],
CNode: baseStyle
}
]

View File

@ -0,0 +1,150 @@
import { c, cTB, cE, cM, cNotM, cB } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const {
boxShadowDefault,
boxShadowActive,
boxShadowFocus,
boxShadowHover,
boxShadowDisabled,
backgroundColorDefault,
backgroundColorDisabled,
labelTextColorDefault,
labelTextColorDisabled,
controlBackgroundColorActive,
controlBackgroundColorDisabled
} = props.$local
const {
easeInOutCubicBezier
} = props.$base
return [
cTB(
'radio',
{
raw: `
line-height: 1.25;
outline: none;
position: relative;
user-select: none;
display: inline-flex;
vertical-align: middle;
align-items: center;
`
},
[
cE('radio-input', {
raw: `
width: 0;
height: 0;
opacity: 0;
margin: 0;
`
}),
cE('control', {
raw: `
transition:
background-color .3s ${easeInOutCubicBezier},
box-shadow .3s ${easeInOutCubicBezier};
margin-right: 9px;
position: relative;
border-radius: 50%;
`,
backgroundColor: backgroundColorDefault,
boxShadow: boxShadowDefault
}
, [
c('&::before', {
raw: `
content: "";
opacity: 0;
position: absolute;
left: 4px;
top: 4px;
height: calc(100% - 8px);
width: calc(100% - 8px);
border-radius: 50%;
transform: scale(.8);
transition:
opacity .3s ${easeInOutCubicBezier},
background-color .3s ${easeInOutCubicBezier},
transform .3s ${easeInOutCubicBezier};
`,
backgroundColor: controlBackgroundColorActive
}),
cM('checked', {
boxShadow: boxShadowActive
}, [
c('&::before', {
raw: `
opacity: 1;
transform: scale(1);
`
})
])
]),
cE('label', {
raw: `
display: inline-block;
white-space: nowrap;
transition: color .3s ${easeInOutCubicBezier};
`,
color: labelTextColorDefault
}),
cNotM('disabled', {
raw: `
cursor: pointer;
`
}, [
c('&:hover', [
cE('control', {
boxShadow: boxShadowHover
})
]),
cM('focus', [
c('&:not(:active)', [
cE('control', {
boxShadow: boxShadowFocus
})
])
])
]),
cM('disabled', {
raw: `
cursor: not-allowed;
`
}, [
cE('control', {
boxShadow: boxShadowDisabled,
backgroundColor: backgroundColorDisabled
}, [
c('&::before', {
backgroundColor: controlBackgroundColorDisabled
}),
cM('checked', {
raw: `
transform: scale(1);
opacity: 1;
`
})
]),
cE('label', {
color: labelTextColorDisabled
})
])
]
),
cTB('radio-group', {
raw: `
display: inline-block;
`
}, [
cB('radio', {
raw: `
margin-right: 18px;
`
})
])
]
}
])

View File

@ -0,0 +1,22 @@
import { c, cB, cE, cM } from '../../../../_utils/cssr'
export default c([
({ props }) => {
const size = props.$instance.syntheticSize
const fontSize = props.$local.fontSize[size]
const radioSize = props.$local.radioSize[size]
return cB(
'radio',
[
cM(`${size}-size`, {
fontSize
}, [
cE('control', {
height: radioSize,
width: radioSize
})
])
]
)
}
])

View File

@ -0,0 +1,21 @@
export default {
height: {
tiny: '22px',
small: ' 28px',
medium: '34px',
large: '40px',
huge: '48px'
},
fontSize: {
tiny: '13px',
small: '14px',
medium: '14px',
large: '15px',
huge: '16px'
},
radioSize: {
small: '14px',
medium: '14px',
large: '16px'
}
}

50
src/radio/styles/dark.js Normal file
View File

@ -0,0 +1,50 @@
import create from '../../styles/_utils/create-component-base'
import { changeColor } from '../../_utils/color'
import commonVariables from './_common'
export default create({
theme: 'dark',
name: 'Radio',
getDerivedVariables ({ base, derived }) {
const {
borderOverlayColor,
primaryColor,
baseBackgroundColor,
disabledTextOverlayColor,
disabledBackgroundColor,
secondaryTextOverlayColor,
disabledOpacity
} = derived
const {
borderRadius
} = base
const borderMaskWidth = '1px'
return {
...commonVariables,
boxShadowDefault: `inset 0 0 0 1px ${borderOverlayColor}`,
boxShadowActive: `inset 0 0 0 1px ${primaryColor}`,
boxShadowFocus: `(inset 0 0 0 1px ${primaryColor}, 0 0 0 2px ${changeColor(primaryColor, { alpha: 0.3 })})`,
boxShadowHover: `inset 0 0 0 1px ${primaryColor}`,
boxShadowDisabled: `inset 0 0 0 1px ${borderOverlayColor}`,
backgroundColorDefault: 'transparent',
backgroundColorDisabled: disabledBackgroundColor,
labelTextColorDefault: secondaryTextOverlayColor,
labelTextColorDisabled: disabledTextOverlayColor,
controlBackgroundColorActive: primaryColor,
controlBackgroundColorDisabled: borderOverlayColor,
buttonBorderColorDefault: borderOverlayColor,
buttonBorderColorActive: primaryColor,
buttonBorderColorHover: primaryColor,
buttonBackgroundColorDefault: 'transparent',
buttonBackgroundColorActive: primaryColor,
buttonLabelColorDefault: secondaryTextOverlayColor,
buttonLabelColorActive: baseBackgroundColor,
buttonLabelColorHover: primaryColor,
disabledOpacity: disabledOpacity,
borderMaskWidth: borderMaskWidth,
buttonBoxShadowFocus: `(inset 0 0 0 1px ${primaryColor}, 0 0 0 2px ${changeColor(primaryColor, { alpha: 0.3 })})`,
buttonBoxShadowHover: `inset 0 0 0 ${borderMaskWidth} ${primaryColor}`,
buttonBorderRadius: borderRadius
}
}
})

50
src/radio/styles/light.js Normal file
View File

@ -0,0 +1,50 @@
import create from '../../styles/_utils/create-component-base'
import { changeColor } from '../../_utils/color'
import commonVariables from './_common'
export default create({
theme: 'light',
name: 'Radio',
getDerivedVariables ({ base, derived }) {
const {
borderColor,
primaryColor,
baseBackgroundColor,
disabledTextColor,
disabledBackgroundColor,
secondaryTextColor,
disabledOpacity
} = derived
const {
borderRadius
} = base
const borderMaskWidth = '0px'
return {
...commonVariables,
boxShadowDefault: `inset 0 0 0 1px ${borderColor}`,
boxShadowActive: `inset 0 0 0 1px ${primaryColor}`,
boxShadowFocus: `(inset 0 0 0 1px ${primaryColor}, 0 0 0 2px ${changeColor(primaryColor, { alpha: 0.3 })})`,
boxShadowHover: `inset 0 0 0 1px ${primaryColor}`,
boxShadowDisabled: `inset 0 0 0 1px ${borderColor}`,
backgroundColorDefault: baseBackgroundColor,
backgroundColorDisabled: disabledBackgroundColor,
labelTextColorDefault: secondaryTextColor,
labelTextColorDisabled: disabledTextColor,
controlBackgroundColorActive: primaryColor,
controlBackgroundColorDisabled: borderColor,
buttonBorderColorDefault: borderColor,
buttonBorderColorActive: primaryColor,
buttonBorderColorHover: borderColor,
buttonBackgroundColorDefault: baseBackgroundColor,
buttonBackgroundColorActive: baseBackgroundColor,
buttonLabelColorDefault: secondaryTextColor,
buttonLabelColorActive: primaryColor,
buttonLabelColorHover: primaryColor,
disabledOpacity: disabledOpacity,
borderMaskWidth: borderMaskWidth,
buttonBoxShadowFocus: `(inset 0 0 0 1px ${primaryColor}, 0 0 0 2px ${changeColor(primaryColor, { alpha: 0.3 })})`,
buttonBoxShadowHover: `inset 0 0 0 ${borderMaskWidth} transparent`,
buttonBorderRadius: borderRadius
}
}
})