mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-06 12:17:13 +08:00
feat(radio): clsPrefix
This commit is contained in:
parent
9d60bb5270
commit
e53f4109fd
@ -1,4 +1,6 @@
|
||||
/* istanbul ignore file */
|
||||
export { default as NRadio } from './src/Radio'
|
||||
export { default as NRadioGroup } from './src/RadioGroup'
|
||||
export { default as NRadioButton } from './src/RadioButton'
|
||||
export type { RadioProps } from './src/Radio'
|
||||
export type { RadioGroupProps } from './src/RadioGroup'
|
||||
export type { RadioButtonProps } from './src/RadioButton'
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { h, defineComponent, computed, CSSProperties } from 'vue'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { createKey } from '../../_utils'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
import { radioLight, RadioTheme } from '../styles'
|
||||
import useRadio from './use-radio'
|
||||
import style from './styles/radio.cssr'
|
||||
import { createKey } from '../../_utils'
|
||||
|
||||
export type RadioProps = ExtractPublicPropTypes<typeof useRadio.props>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Radio',
|
||||
@ -13,8 +16,15 @@ export default defineComponent({
|
||||
...useRadio.props
|
||||
},
|
||||
setup (props) {
|
||||
const themeRef = useTheme('Radio', 'Radio', style, radioLight, props)
|
||||
const radio = useRadio(props)
|
||||
const themeRef = useTheme(
|
||||
'Radio',
|
||||
'Radio',
|
||||
style,
|
||||
radioLight,
|
||||
props,
|
||||
radio.cPrefix
|
||||
)
|
||||
return Object.assign(radio, {
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
@ -60,15 +70,15 @@ export default defineComponent({
|
||||
})
|
||||
},
|
||||
render () {
|
||||
const { $slots } = this
|
||||
const { $slots, cPrefix } = this
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-radio',
|
||||
`${cPrefix}-radio`,
|
||||
{
|
||||
'n-radio--disabled': this.mergedDisabled,
|
||||
'n-radio--checked': this.renderSafeChecked,
|
||||
'n-radio--focus': this.focus
|
||||
[`${cPrefix}-radio--disabled`]: this.mergedDisabled,
|
||||
[`${cPrefix}-radio--checked`]: this.renderSafeChecked,
|
||||
[`${cPrefix}-radio--focus`]: this.focus
|
||||
}
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
@ -79,7 +89,7 @@ export default defineComponent({
|
||||
<input
|
||||
ref="inputRef"
|
||||
type="radio"
|
||||
class="n-radio__radio-input"
|
||||
class={`${cPrefix}-radio__radio-input`}
|
||||
value={this.value}
|
||||
name={this.mergedName}
|
||||
checked={this.renderSafeChecked}
|
||||
@ -90,14 +100,12 @@ export default defineComponent({
|
||||
/>
|
||||
<div
|
||||
class={[
|
||||
'n-radio__dot',
|
||||
{
|
||||
'n-radio__dot--checked': this.renderSafeChecked
|
||||
}
|
||||
`${cPrefix}-radio__dot`,
|
||||
this.renderSafeChecked && `${cPrefix}-radio__dot--checked`
|
||||
]}
|
||||
/>
|
||||
{$slots.default ? (
|
||||
<div ref="labelRef" class="n-radio__label">
|
||||
<div ref="labelRef" class={`${cPrefix}-radio__label`}>
|
||||
{$slots.default()}
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { h, defineComponent } from 'vue'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
import useRadio from './use-radio'
|
||||
|
||||
export type RadioButtonProps = ExtractPublicPropTypes<typeof useRadio.props>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RadioButton',
|
||||
props: useRadio.props,
|
||||
@ -8,14 +11,15 @@ export default defineComponent({
|
||||
return useRadio(props)
|
||||
},
|
||||
render () {
|
||||
const { cPrefix } = this
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-radio-button',
|
||||
`${cPrefix}-radio-button`,
|
||||
{
|
||||
'n-radio-button--disabled': this.mergedDisabled,
|
||||
'n-radio-button--checked': this.renderSafeChecked,
|
||||
'n-radio-button--focus': this.focus
|
||||
[`${cPrefix}-radio-button--disabled`]: this.mergedDisabled,
|
||||
[`${cPrefix}-radio-button--checked`]: this.renderSafeChecked,
|
||||
[`${cPrefix}-radio-button--focus`]: this.focus
|
||||
}
|
||||
]}
|
||||
onKeyup={this.handleKeyUp}
|
||||
@ -25,7 +29,7 @@ export default defineComponent({
|
||||
<input
|
||||
ref="inputRef"
|
||||
type="radio"
|
||||
class="n-radio-button__radio-input"
|
||||
class={`${cPrefix}-radio-button__radio-input`}
|
||||
value={this.value}
|
||||
name={this.mergedName}
|
||||
checked={this.renderSafeChecked}
|
||||
@ -34,7 +38,7 @@ export default defineComponent({
|
||||
onFocus={this.handleRadioInputFocus}
|
||||
onBlur={this.handleRadioInputBlur}
|
||||
/>
|
||||
<div class="n-radio-button__state-border" />
|
||||
<div class={`${cPrefix}-radio-button__state-border`} />
|
||||
<span ref="labelRef">{this.$slots}</span>
|
||||
</div>
|
||||
)
|
||||
|
@ -7,22 +7,24 @@ import {
|
||||
provide,
|
||||
ref,
|
||||
toRef,
|
||||
reactive,
|
||||
VNodeChild,
|
||||
CSSProperties
|
||||
} from 'vue'
|
||||
import { useMergedState } from 'vooks'
|
||||
import { useTheme, useFormItem } from '../../_mixins'
|
||||
import { useTheme, useFormItem, useConfig } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { getSlot, warn, createKey, call, flatten } from '../../_utils'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
import { radioLight } from '../styles'
|
||||
import type { RadioTheme } from '../styles'
|
||||
import type { RadioProps, RadioGroupInjection } from './use-radio'
|
||||
import type { RadioProps } from './use-radio'
|
||||
import { radioGroupInjectionKey } from './use-radio'
|
||||
import style from './styles/radio-group.cssr'
|
||||
|
||||
function mapSlot (
|
||||
defaultSlot: VNode[],
|
||||
value: string | number | null
|
||||
value: string | number | null,
|
||||
clsPrefix: string
|
||||
): {
|
||||
children: VNodeChild[]
|
||||
isButtonGroup: boolean
|
||||
@ -68,19 +70,19 @@ function mapSlot (
|
||||
const currentInstancePriority =
|
||||
(currentInstanceChecked ? 2 : 0) + (!currentInstanceDisabled ? 1 : 0)
|
||||
const lastInstanceClass = {
|
||||
'n-radio-group__splitor--disabled': lastInstanceDisabled,
|
||||
'n-radio-group__splitor--checked': lastInstanceChecked
|
||||
[`${clsPrefix}-radio-group__splitor--disabled`]: lastInstanceDisabled,
|
||||
[`${clsPrefix}-radio-group__splitor--checked`]: lastInstanceChecked
|
||||
}
|
||||
const currentInstanceClass = {
|
||||
'n-radio-group__splitor--disabled': currentInstanceDisabled,
|
||||
'n-radio-group__splitor--checked': currentInstanceChecked
|
||||
[`${clsPrefix}-radio-group__splitor--disabled`]: currentInstanceDisabled,
|
||||
[`${clsPrefix}-radio-group__splitor--checked`]: currentInstanceChecked
|
||||
}
|
||||
const splitorClass =
|
||||
lastInstancePriority < currentInstancePriority
|
||||
? currentInstanceClass
|
||||
: lastInstanceClass
|
||||
children.push(
|
||||
<div class={['n-radio-group__splitor', splitorClass]}></div>,
|
||||
<div class={[`${clsPrefix}-radio-group__splitor`, splitorClass]}></div>,
|
||||
wrappedInstance
|
||||
)
|
||||
}
|
||||
@ -91,49 +93,61 @@ function mapSlot (
|
||||
}
|
||||
}
|
||||
|
||||
const radioGroupProps = {
|
||||
...(useTheme.props as ThemeProps<RadioTheme>),
|
||||
name: String,
|
||||
value: {
|
||||
type: [String, Number] as PropType<string | number | undefined | null>
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Number] as PropType<string | number | null>,
|
||||
default: null
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large' | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': Function as PropType<(value: string | number) => void>,
|
||||
onUpdateValue: Function as PropType<(value: string | number) => void>,
|
||||
// deprecated
|
||||
onChange: {
|
||||
type: (Function as unknown) as PropType<
|
||||
((value: string | number) => void) | undefined
|
||||
>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'radio-group',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
} as const
|
||||
|
||||
export type RadioGroupProps = ExtractPublicPropTypes<typeof radioGroupProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RadioGroup',
|
||||
props: {
|
||||
...(useTheme.props as ThemeProps<RadioTheme>),
|
||||
name: String,
|
||||
value: {
|
||||
type: [String, Number] as PropType<string | number | undefined | null>
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Number] as PropType<string | number | null>,
|
||||
default: null
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large' | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': Function as PropType<(value: string | number) => void>,
|
||||
onUpdateValue: Function as PropType<(value: string | number) => void>,
|
||||
// deprecated
|
||||
onChange: {
|
||||
type: (Function as unknown) as PropType<
|
||||
((value: string | number) => void) | undefined
|
||||
>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'radio-group',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
props: radioGroupProps,
|
||||
setup (props) {
|
||||
const formItem = useFormItem(props)
|
||||
const themeRef = useTheme('Radio', 'RadioGroup', style, radioLight, props)
|
||||
const { mergedClsPrefix } = useConfig(props)
|
||||
const themeRef = useTheme(
|
||||
'Radio',
|
||||
'RadioGroup',
|
||||
style,
|
||||
radioLight,
|
||||
props,
|
||||
mergedClsPrefix
|
||||
)
|
||||
const { mergedSize: mergedSizeRef } = formItem
|
||||
const uncontrolledValueRef = ref(props.defaultValue)
|
||||
const controlledValueRef = toRef(props, 'value')
|
||||
@ -158,17 +172,16 @@ export default defineComponent({
|
||||
}
|
||||
uncontrolledValueRef.value = value
|
||||
}
|
||||
provide<RadioGroupInjection>(
|
||||
'NRadioGroup',
|
||||
reactive({
|
||||
name: toRef(props, 'name'),
|
||||
value: mergedValueRef,
|
||||
doUpdateValue,
|
||||
disabled: toRef(props, 'disabled'),
|
||||
mergedSize: formItem.mergedSize
|
||||
})
|
||||
)
|
||||
provide(radioGroupInjectionKey, {
|
||||
cPrefixRef: mergedClsPrefix,
|
||||
nameRef: toRef(props, 'name'),
|
||||
valueRef: mergedValueRef,
|
||||
disabledRef: toRef(props, 'disabled'),
|
||||
mergedSizeRef: formItem.mergedSize,
|
||||
doUpdateValue
|
||||
})
|
||||
return {
|
||||
cPrefix: mergedClsPrefix,
|
||||
mergedValue: mergedValueRef,
|
||||
cssVars: computed(() => {
|
||||
const { value: size } = mergedSizeRef
|
||||
@ -208,16 +221,17 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { mergedValue } = this
|
||||
const { mergedValue, cPrefix } = this
|
||||
const { children, isButtonGroup } = mapSlot(
|
||||
flatten(getSlot(this)),
|
||||
mergedValue
|
||||
mergedValue,
|
||||
cPrefix
|
||||
)
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-radio-group',
|
||||
isButtonGroup && 'n-radio-group--button-group'
|
||||
`${cPrefix}-radio-group`,
|
||||
isButtonGroup && `${cPrefix}-radio-group--button-group`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
|
@ -5,11 +5,13 @@ import {
|
||||
ExtractPropTypes,
|
||||
PropType,
|
||||
Ref,
|
||||
ComputedRef
|
||||
ComputedRef,
|
||||
InjectionKey
|
||||
} from 'vue'
|
||||
import { useMemo, useMergedState } from 'vooks'
|
||||
import { useFormItem } from '../../_mixins'
|
||||
import { warn, call, MaybeArray } from '../../_utils'
|
||||
import { useConfig, useFormItem } from '../../_mixins'
|
||||
import { warn, call } from '../../_utils'
|
||||
import type { MaybeArray } from '../../_utils'
|
||||
|
||||
const radioProps = {
|
||||
name: String,
|
||||
@ -48,14 +50,20 @@ const radioProps = {
|
||||
} as const
|
||||
|
||||
export interface RadioGroupInjection {
|
||||
name: string | undefined
|
||||
value: string | number | null
|
||||
mergedSize: 'small' | 'medium' | 'large'
|
||||
disabled: boolean
|
||||
cPrefixRef: Ref<string>
|
||||
nameRef: Ref<string | undefined>
|
||||
valueRef: Ref<string | number | null>
|
||||
mergedSizeRef: Ref<'small' | 'medium' | 'large'>
|
||||
disabledRef: Ref<boolean>
|
||||
doUpdateValue: (value: string | number) => void
|
||||
}
|
||||
|
||||
export const radioGroupInjectionKey: InjectionKey<RadioGroupInjection> = Symbol(
|
||||
'radioGroup'
|
||||
)
|
||||
|
||||
export interface UseRadio {
|
||||
cPrefix: Ref<string>
|
||||
inputRef: Ref<HTMLElement | null>
|
||||
labelRef: Ref<HTMLElement | null>
|
||||
mergedName: Ref<string | undefined>
|
||||
@ -78,7 +86,9 @@ function setup (props: ExtractPropTypes<typeof radioProps>): UseRadio {
|
||||
const { size } = props
|
||||
if (size !== undefined) return size
|
||||
if (NRadioGroup) {
|
||||
const { mergedSize } = NRadioGroup
|
||||
const {
|
||||
mergedSizeRef: { value: mergedSize }
|
||||
} = NRadioGroup
|
||||
if (mergedSize !== undefined) {
|
||||
return mergedSize
|
||||
}
|
||||
@ -91,7 +101,7 @@ function setup (props: ExtractPropTypes<typeof radioProps>): UseRadio {
|
||||
})
|
||||
const inputRef = ref<HTMLElement | null>(null)
|
||||
const labelRef = ref<HTMLElement | null>(null)
|
||||
const NRadioGroup = inject<RadioGroupInjection | null>('NRadioGroup', null)
|
||||
const NRadioGroup = inject(radioGroupInjectionKey, null)
|
||||
const uncontrolledCheckedRef = ref(props.defaultChecked)
|
||||
const controlledCheckedRef = toRef(props, 'checked')
|
||||
const mergedCheckedRef = useMergedState(
|
||||
@ -99,16 +109,16 @@ function setup (props: ExtractPropTypes<typeof radioProps>): UseRadio {
|
||||
uncontrolledCheckedRef
|
||||
)
|
||||
const renderSafeCheckedRef = useMemo(() => {
|
||||
if (NRadioGroup) return NRadioGroup.value === props.value
|
||||
if (NRadioGroup) return NRadioGroup.valueRef.value === props.value
|
||||
return mergedCheckedRef.value
|
||||
})
|
||||
const mergedNameRef = useMemo(() => {
|
||||
const { name } = props
|
||||
if (name !== undefined) return name
|
||||
if (NRadioGroup) return NRadioGroup.name
|
||||
if (NRadioGroup) return NRadioGroup.nameRef.value
|
||||
})
|
||||
const mergedDisabledRef = useMemo(() => {
|
||||
return NRadioGroup?.disabled || props.disabled
|
||||
return NRadioGroup?.disabledRef.value || props.disabled
|
||||
})
|
||||
const focusRef = ref(false)
|
||||
function doUpdateChecked (): void {
|
||||
@ -158,6 +168,9 @@ function setup (props: ExtractPropTypes<typeof radioProps>): UseRadio {
|
||||
inputRef.value?.click()
|
||||
}
|
||||
return {
|
||||
cPrefix: NRadioGroup
|
||||
? NRadioGroup.cPrefixRef
|
||||
: useConfig(props).mergedClsPrefix,
|
||||
inputRef,
|
||||
labelRef,
|
||||
mergedName: mergedNameRef,
|
||||
|
Loading…
Reference in New Issue
Block a user