diff --git a/components/_util/createContext.ts b/components/_util/createContext.ts new file mode 100644 index 000000000..aa68a11e8 --- /dev/null +++ b/components/_util/createContext.ts @@ -0,0 +1,17 @@ +import { inject, provide } from 'vue'; + +function createContext() { + const contextKey = Symbol('contextKey'); + const useProvide = (props: T) => { + provide(contextKey, props); + }; + const useInject = () => { + return inject(contextKey, undefined as T) || ({} as T); + }; + return { + useProvide, + useInject, + }; +} + +export default createContext; diff --git a/components/button/button-group.tsx b/components/button/button-group.tsx index fd543d9ff..19c2bf42a 100644 --- a/components/button/button-group.tsx +++ b/components/button/button-group.tsx @@ -2,9 +2,10 @@ import { computed, defineComponent } from 'vue'; import { flattenChildren } from '../_util/props-util'; import useConfigInject from '../_util/hooks/useConfigInject'; -import type { ExtractPropTypes, PropType } from 'vue'; +import type { ExtractPropTypes, PropType, ComputedRef } from 'vue'; import type { SizeType } from '../config-provider'; -import UnreachableException from '../_util/unreachableException'; +import devWarning from '../vc-util/devWarning'; +import createContext from '../_util/createContext'; export const buttonGroupProps = () => ({ prefixCls: String, @@ -14,12 +15,17 @@ export const buttonGroupProps = () => ({ }); export type ButtonGroupProps = Partial>>; - +export const GroupSizeContext = createContext<{ + size: ComputedRef; +}>(); export default defineComponent({ name: 'AButtonGroup', props: buttonGroupProps(), setup(props, { slots }) { const { prefixCls, direction } = useConfigInject('btn-group', props); + GroupSizeContext.useProvide({ + size: computed(() => props.size), + }); const classes = computed(() => { const { size } = props; // large => lg @@ -37,7 +43,7 @@ export default defineComponent({ break; default: // eslint-disable-next-line no-console - console.warn(new UnreachableException(size).error); + devWarning(!size, 'Button.Group', 'Invalid prop `size`.'); } return { [`${prefixCls.value}`]: true, diff --git a/components/button/button.tsx b/components/button/button.tsx index d5a1a3960..658a42ce0 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -18,13 +18,14 @@ import LoadingIcon from './LoadingIcon'; import type { ButtonType } from './buttonTypes'; import type { VNode, Ref } from 'vue'; +import { GroupSizeContext } from './button-group'; type Loading = boolean | number; const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/; const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar); -function isUnborderedButtonType(type: ButtonType | undefined) { +function isUnBorderedButtonType(type: ButtonType | undefined) { return type === 'text' || type === 'link'; } export { buttonProps }; @@ -37,7 +38,7 @@ export default defineComponent({ // emits: ['click', 'mousedown'], setup(props, { slots, attrs, emit }) { const { prefixCls, autoInsertSpaceInButton, direction, size } = useConfigInject('btn', props); - + const { size: groupSize } = GroupSizeContext.useInject(); const buttonNodeRef = ref(null); const delayTimeoutRef = ref(undefined); let isNeedInserted = false; @@ -76,7 +77,7 @@ export default defineComponent({ const pre = prefixCls.value; const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined }; - const sizeFullname = size.value; + const sizeFullname = groupSize?.value || size.value; const sizeCls = sizeFullname ? sizeClassNameMap[sizeFullname] || '' : ''; return { @@ -85,7 +86,7 @@ export default defineComponent({ [`${pre}-${shape}`]: shape !== 'default' && shape, [`${pre}-${sizeCls}`]: sizeCls, [`${pre}-loading`]: innerLoading.value, - [`${pre}-background-ghost`]: ghost && !isUnborderedButtonType(type), + [`${pre}-background-ghost`]: ghost && !isUnBorderedButtonType(type), [`${pre}-two-chinese-chars`]: hasTwoCNChar.value && autoInsertSpace.value, [`${pre}-block`]: block, [`${pre}-dangerous`]: !!danger, @@ -132,7 +133,7 @@ export default defineComponent({ watchEffect(() => { devWarning( - !(props.ghost && isUnborderedButtonType(props.type)), + !(props.ghost && isUnBorderedButtonType(props.type)), 'Button', "`link` or `text` button can't be a `ghost` button.", ); @@ -149,7 +150,7 @@ export default defineComponent({ const { icon = slots.icon?.() } = props; const children = flattenChildren(slots.default?.()); - isNeedInserted = children.length === 1 && !icon && !isUnborderedButtonType(props.type); + isNeedInserted = children.length === 1 && !icon && !isUnBorderedButtonType(props.type); const { type, htmlType, disabled, href, title, target, onMousedown } = props; @@ -202,7 +203,7 @@ export default defineComponent({ ); - if (isUnborderedButtonType(type)) { + if (isUnBorderedButtonType(type)) { return buttonNode; } diff --git a/components/button/style/mixin.less b/components/button/style/mixin.less index 96efadc8d..084ecaa5b 100644 --- a/components/button/style/mixin.less +++ b/components/button/style/mixin.less @@ -210,28 +210,6 @@ .@{btnClassName}-icon-only { font-size: @font-size-base; } - // size - &-lg > .@{btnClassName}, - &-lg > span > .@{btnClassName} { - .button-size(@btn-height-lg; @btn-padding-horizontal-lg; @btn-font-size-lg; 0); - } - &-lg .@{btnClassName}.@{btnClassName}-icon-only { - .square(@btn-height-lg); - padding-right: 0; - padding-left: 0; - } - &-sm > .@{btnClassName}, - &-sm > span > .@{btnClassName} { - .button-size(@btn-height-sm; @btn-padding-horizontal-sm; @font-size-base; 0); - > .@{iconfont-css-prefix} { - font-size: @font-size-base; - } - } - &-sm .@{btnClassName}.@{btnClassName}-icon-only { - .square(@btn-height-sm); - padding-right: 0; - padding-left: 0; - } } // Base styles of buttons // --------------------------------------------------