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 './DatePicker.scss';
@import './Descriptions.scss';
// @import './Radio.scss';
@import './Form.scss';
@import './Grid.scss';
@import './Layout.scss';

View File

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

View File

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

View File

@ -47,7 +47,7 @@ import Popconfirm from './popconfirm'
import Popselect from './popselect'
import Popup from './Popover'
import Progress from './progress'
import Radio from './Radio'
import Radio from './radio'
import Result from './result'
import Select from './select'
import Scrollbar from './scrollbar'
@ -168,6 +168,8 @@ import thingLightStyle from './thing/styles/light'
import thingDarkStyle from './thing/styles/dark'
import switchLightStyle from './switch/styles/light'
import switchDarkStyle from './switch/styles/dark'
import radioLightStyle from './radio/styles/light'
import radioDarkStyle from './radio/styles/dark'
// Can be remove after refactoring
import baseSelectionLightStyle from './_base/selection/styles/light'
@ -365,6 +367,8 @@ export default create({
thingDarkStyle,
switchLightStyle,
switchDarkStyle,
radioLightStyle,
radioDarkStyle,
// Can be remove after refactoring
baseSelectionLightStyle,
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 themeable from '../../_mixins/themeable'
import radioMixin from './radioMixin'
import usecssr from '../../_mixins/usecssr'
import styles from './styles/radio/index.js'
export default {
name: 'NRadio',
mixins: [ withapp, themeable, asformitem(
{
change: 'change',
blur: 'blur',
focus: 'focus'
},
'medium',
function () {
const size = this.size
if (size) return size
const NRadioGroup = this.NRadioGroup
if (NRadioGroup && NRadioGroup.syntheticSize) {
return NRadioGroup.syntheticSize
}
const NFormItem = this.NFormItem
if (
NFormItem &&
name: 'Radio',
mixins: [
withapp,
themeable,
usecssr(styles),
asformitem(
{
change: 'change',
blur: 'blur',
focus: 'focus'
},
'medium',
function () {
const size = this.size
if (size) return size
const NRadioGroup = this.NRadioGroup
if (NRadioGroup && NRadioGroup.syntheticSize) {
return NRadioGroup.syntheticSize
}
const NFormItem = this.NFormItem
if (
NFormItem &&
NFormItem !== '__FORM_ITEM_INNER__' &&
NFormItem.syntheticSize
) {
return NFormItem.syntheticSize
) {
return NFormItem.syntheticSize
}
return 'medium'
}
return 'medium'
}
), radioMixin ],
), radioMixin ],
props: {
size: {
validator (value) {

View File

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

View File

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