From e53f4109fd9ed8ba4e79bfd509c9c1d90c78abf9 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Sun, 18 Apr 2021 00:07:55 +0800 Subject: [PATCH] feat(radio): clsPrefix --- src/radio/index.ts | 4 +- src/radio/src/Radio.tsx | 34 +++++---- src/radio/src/RadioButton.tsx | 16 ++-- src/radio/src/RadioGroup.tsx | 138 +++++++++++++++++++--------------- src/radio/src/use-radio.ts | 37 ++++++--- 5 files changed, 135 insertions(+), 94 deletions(-) diff --git a/src/radio/index.ts b/src/radio/index.ts index 9efbc0c57..4e43c174d 100644 --- a/src/radio/index.ts +++ b/src/radio/index.ts @@ -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' diff --git a/src/radio/src/Radio.tsx b/src/radio/src/Radio.tsx index 826b0b3f5..b2ef24cd5 100644 --- a/src/radio/src/Radio.tsx +++ b/src/radio/src/Radio.tsx @@ -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 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 (
{$slots.default ? ( -
+
{$slots.default()}
) : null} diff --git a/src/radio/src/RadioButton.tsx b/src/radio/src/RadioButton.tsx index f574eb64d..d029acaf0 100644 --- a/src/radio/src/RadioButton.tsx +++ b/src/radio/src/RadioButton.tsx @@ -1,6 +1,9 @@ import { h, defineComponent } from 'vue' +import type { ExtractPublicPropTypes } from '../../_utils' import useRadio from './use-radio' +export type RadioButtonProps = ExtractPublicPropTypes + export default defineComponent({ name: 'RadioButton', props: useRadio.props, @@ -8,14 +11,15 @@ export default defineComponent({ return useRadio(props) }, render () { + const { cPrefix } = this return (
-
+
{this.$slots}
) diff --git a/src/radio/src/RadioGroup.tsx b/src/radio/src/RadioGroup.tsx index 45cae2f82..01ef2369e 100644 --- a/src/radio/src/RadioGroup.tsx +++ b/src/radio/src/RadioGroup.tsx @@ -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( -
, +
, wrappedInstance ) } @@ -91,49 +93,61 @@ function mapSlot ( } } +const radioGroupProps = { + ...(useTheme.props as ThemeProps), + name: String, + value: { + type: [String, Number] as PropType + }, + defaultValue: { + type: [String, Number] as PropType, + 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 + export default defineComponent({ name: 'RadioGroup', - props: { - ...(useTheme.props as ThemeProps), - name: String, - value: { - type: [String, Number] as PropType - }, - defaultValue: { - type: [String, Number] as PropType, - 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( - '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 (
diff --git a/src/radio/src/use-radio.ts b/src/radio/src/use-radio.ts index eb3f7737a..58b0c5e45 100644 --- a/src/radio/src/use-radio.ts +++ b/src/radio/src/use-radio.ts @@ -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 + nameRef: Ref + valueRef: Ref + mergedSizeRef: Ref<'small' | 'medium' | 'large'> + disabledRef: Ref doUpdateValue: (value: string | number) => void } +export const radioGroupInjectionKey: InjectionKey = Symbol( + 'radioGroup' +) + export interface UseRadio { + cPrefix: Ref inputRef: Ref labelRef: Ref mergedName: Ref @@ -78,7 +86,9 @@ function setup (props: ExtractPropTypes): 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): UseRadio { }) const inputRef = ref(null) const labelRef = ref(null) - const NRadioGroup = inject('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): 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): UseRadio { inputRef.value?.click() } return { + cPrefix: NRadioGroup + ? NRadioGroup.cPrefixRef + : useConfig(props).mergedClsPrefix, inputRef, labelRef, mergedName: mergedNameRef,