refactor(v3/badge): use composition api (#4076)
parent
69b9f80a01
commit
372ac5c729
|
@ -1,27 +1,39 @@
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import ScrollNumber from './ScrollNumber';
|
||||
import classNames from '../_util/classNames';
|
||||
import { initDefaultProps, getComponent, getSlot } from '../_util/props-util';
|
||||
import { getPropsSlot, flattenChildren } from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import isNumeric from '../_util/isNumeric';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import { inject, defineComponent, CSSProperties, VNode, App, Plugin } from 'vue';
|
||||
import {
|
||||
inject,
|
||||
defineComponent,
|
||||
ExtractPropTypes,
|
||||
CSSProperties,
|
||||
VNode,
|
||||
App,
|
||||
Plugin,
|
||||
reactive,
|
||||
computed,
|
||||
} from 'vue';
|
||||
import { tuple } from '../_util/type';
|
||||
import Ribbon from './Ribbon';
|
||||
import { isPresetColor } from './utils';
|
||||
|
||||
const BadgeProps = {
|
||||
export const badgeProps = {
|
||||
/** Number to show in badge */
|
||||
count: PropTypes.VNodeChild,
|
||||
showZero: PropTypes.looseBool,
|
||||
/** Max count to show */
|
||||
overflowCount: PropTypes.number,
|
||||
overflowCount: PropTypes.number.def(99),
|
||||
/** whether to show red dot without number */
|
||||
dot: PropTypes.looseBool,
|
||||
prefixCls: PropTypes.string,
|
||||
scrollNumberPrefixCls: PropTypes.string,
|
||||
status: PropTypes.oneOf(tuple('success', 'processing', 'default', 'error', 'warning')),
|
||||
// sync antd@4.6.0
|
||||
size: PropTypes.oneOf(tuple('default', 'small')).def('default'),
|
||||
color: PropTypes.string,
|
||||
text: PropTypes.VNodeChild,
|
||||
offset: PropTypes.arrayOf(PropTypes.oneOfType([String, Number])),
|
||||
|
@ -29,48 +41,44 @@ const BadgeProps = {
|
|||
title: PropTypes.string,
|
||||
};
|
||||
|
||||
export type BadgeProps = Partial<ExtractPropTypes<typeof badgeProps>>;
|
||||
|
||||
const Badge = defineComponent({
|
||||
name: 'ABadge',
|
||||
Ribbon,
|
||||
props: initDefaultProps(BadgeProps, {
|
||||
showZero: false,
|
||||
dot: false,
|
||||
overflowCount: 99,
|
||||
}) as typeof BadgeProps,
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
props: badgeProps,
|
||||
setup(props, { slots }) {
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
const state = reactive({
|
||||
badgeCount: undefined,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getNumberedDispayCount() {
|
||||
const { overflowCount } = this.$props;
|
||||
const count = this.badgeCount;
|
||||
});
|
||||
|
||||
const getNumberedDispayCount = () => {
|
||||
const { overflowCount } = props;
|
||||
const count = state.badgeCount;
|
||||
const displayCount = count > overflowCount ? `${overflowCount}+` : count;
|
||||
return displayCount;
|
||||
},
|
||||
};
|
||||
|
||||
getDispayCount() {
|
||||
const isDot = this.isDot();
|
||||
const getDispayCount = computed(() => {
|
||||
// dot mode don't need count
|
||||
if (isDot) {
|
||||
if (isDot.value) {
|
||||
return '';
|
||||
}
|
||||
return this.getNumberedDispayCount();
|
||||
},
|
||||
return getNumberedDispayCount();
|
||||
});
|
||||
|
||||
getScrollNumberTitle() {
|
||||
const { title } = this.$props;
|
||||
const count = this.badgeCount;
|
||||
const getScrollNumberTitle = () => {
|
||||
const { title } = props;
|
||||
const count = state.badgeCount;
|
||||
if (title) {
|
||||
return title;
|
||||
}
|
||||
return typeof count === 'string' || typeof count === 'number' ? count : undefined;
|
||||
},
|
||||
};
|
||||
|
||||
getStyleWithOffset() {
|
||||
const { offset, numberStyle } = this.$props;
|
||||
const getStyleWithOffset = () => {
|
||||
const { offset, numberStyle } = props;
|
||||
return offset
|
||||
? {
|
||||
right: `${-parseInt(offset[0] as string, 10)}px`,
|
||||
|
@ -78,47 +86,49 @@ const Badge = defineComponent({
|
|||
...numberStyle,
|
||||
}
|
||||
: { ...numberStyle };
|
||||
},
|
||||
getBadgeClassName(prefixCls: string, children: VNode[]) {
|
||||
const hasStatus = this.hasStatus();
|
||||
};
|
||||
|
||||
const hasStatus = computed(() => {
|
||||
const { status, color } = props;
|
||||
return !!status || !!color;
|
||||
});
|
||||
|
||||
const isZero = computed(() => {
|
||||
const numberedDispayCount = getNumberedDispayCount();
|
||||
return numberedDispayCount === '0' || numberedDispayCount === 0;
|
||||
});
|
||||
|
||||
const isDot = computed(() => {
|
||||
const { dot } = props;
|
||||
return (dot && !isZero.value) || hasStatus.value;
|
||||
});
|
||||
|
||||
const isHidden = computed(() => {
|
||||
const { showZero } = props;
|
||||
const isEmpty =
|
||||
getDispayCount.value === null ||
|
||||
getDispayCount.value === undefined ||
|
||||
getDispayCount.value === '';
|
||||
return (isEmpty || (isZero.value && !showZero)) && !isDot.value;
|
||||
});
|
||||
|
||||
const renderStatusText = (prefixCls: string) => {
|
||||
const text = getPropsSlot(slots, props, 'text');
|
||||
const hidden = isHidden.value;
|
||||
return hidden || !text ? null : <span class={`${prefixCls}-status-text`}>{text}</span>;
|
||||
};
|
||||
|
||||
const getBadgeClassName = (prefixCls: string, children: VNode[]) => {
|
||||
const status = hasStatus.value;
|
||||
return classNames(prefixCls, {
|
||||
[`${prefixCls}-status`]: hasStatus,
|
||||
[`${prefixCls}-dot-status`]: hasStatus && this.dot && !this.isZero(),
|
||||
[`${prefixCls}-status`]: status,
|
||||
[`${prefixCls}-dot-status`]: status && props.dot && !isZero.value,
|
||||
[`${prefixCls}-not-a-wrapper`]: !children.length,
|
||||
});
|
||||
},
|
||||
hasStatus() {
|
||||
const { status, color } = this.$props;
|
||||
return !!status || !!color;
|
||||
},
|
||||
isZero() {
|
||||
const numberedDispayCount = this.getNumberedDispayCount();
|
||||
return numberedDispayCount === '0' || numberedDispayCount === 0;
|
||||
},
|
||||
};
|
||||
|
||||
isDot() {
|
||||
const { dot } = this.$props;
|
||||
const isZero = this.isZero();
|
||||
return (dot && !isZero) || this.hasStatus();
|
||||
},
|
||||
|
||||
isHidden() {
|
||||
const { showZero } = this.$props;
|
||||
const displayCount = this.getDispayCount();
|
||||
const isZero = this.isZero();
|
||||
const isDot = this.isDot();
|
||||
const isEmpty = displayCount === null || displayCount === undefined || displayCount === '';
|
||||
return (isEmpty || (isZero && !showZero)) && !isDot;
|
||||
},
|
||||
|
||||
renderStatusText(prefixCls: string) {
|
||||
const text = getComponent(this, 'text');
|
||||
const hidden = this.isHidden();
|
||||
return hidden || !text ? null : <span class={`${prefixCls}-status-text`}>{text}</span>;
|
||||
},
|
||||
|
||||
renderDispayComponent() {
|
||||
const count = this.badgeCount;
|
||||
const renderDispayComponent = () => {
|
||||
const count = state.badgeCount;
|
||||
const customNode = count;
|
||||
if (!customNode || typeof customNode !== 'object') {
|
||||
return undefined;
|
||||
|
@ -126,103 +136,102 @@ const Badge = defineComponent({
|
|||
return cloneElement(
|
||||
customNode,
|
||||
{
|
||||
style: this.getStyleWithOffset(),
|
||||
style: getStyleWithOffset(),
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
renderBadgeNumber(prefixCls: string, scrollNumberPrefixCls: string) {
|
||||
const { status, color } = this.$props;
|
||||
const count = this.badgeCount;
|
||||
const displayCount = this.getDispayCount();
|
||||
const isDot = this.isDot();
|
||||
const hidden = this.isHidden();
|
||||
const renderBadgeNumber = (prefixCls: string, scrollNumberPrefixCls: string) => {
|
||||
const { status, color, size } = props;
|
||||
const count = state.badgeCount;
|
||||
const displayCount = getDispayCount.value;
|
||||
|
||||
const scrollNumberCls = {
|
||||
[`${prefixCls}-dot`]: isDot,
|
||||
[`${prefixCls}-count`]: !isDot,
|
||||
[`${prefixCls}-dot`]: isDot.value,
|
||||
[`${prefixCls}-count`]: !isDot.value,
|
||||
[`${prefixCls}-count-sm`]: size === 'small',
|
||||
[`${prefixCls}-multiple-words`]:
|
||||
!isDot && count && count.toString && count.toString().length > 1,
|
||||
!isDot.value && count && count.toString && count.toString().length > 1,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-status-${color}`]: isPresetColor(color),
|
||||
};
|
||||
|
||||
let statusStyle = this.getStyleWithOffset();
|
||||
let statusStyle = getStyleWithOffset();
|
||||
if (color && !isPresetColor(color)) {
|
||||
statusStyle = statusStyle || {};
|
||||
statusStyle.background = color;
|
||||
}
|
||||
|
||||
return hidden ? null : (
|
||||
return isHidden.value ? null : (
|
||||
<ScrollNumber
|
||||
prefixCls={scrollNumberPrefixCls}
|
||||
data-show={!hidden}
|
||||
v-show={!hidden}
|
||||
data-show={!isHidden.value}
|
||||
v-show={!isHidden.value}
|
||||
class={scrollNumberCls}
|
||||
count={displayCount}
|
||||
displayComponent={this.renderDispayComponent()}
|
||||
title={this.getScrollNumberTitle()}
|
||||
displayComponent={renderDispayComponent()}
|
||||
title={getScrollNumberTitle()}
|
||||
style={statusStyle}
|
||||
key="scrollNumber"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
|
||||
status,
|
||||
color,
|
||||
} = this;
|
||||
return () => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
|
||||
status,
|
||||
color,
|
||||
} = props;
|
||||
|
||||
const text = getComponent(this, 'text');
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('badge', customizePrefixCls);
|
||||
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
|
||||
const text = getPropsSlot(slots, props, 'text');
|
||||
const getPrefixCls = configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('badge', customizePrefixCls);
|
||||
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
|
||||
|
||||
const children = getSlot(this);
|
||||
let count = getComponent(this, 'count');
|
||||
if (Array.isArray(count)) {
|
||||
count = count[0];
|
||||
}
|
||||
this.badgeCount = count;
|
||||
const scrollNumber = this.renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
|
||||
const statusText = this.renderStatusText(prefixCls);
|
||||
const statusCls = classNames({
|
||||
[`${prefixCls}-status-dot`]: this.hasStatus(),
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-status-${color}`]: isPresetColor(color),
|
||||
});
|
||||
const statusStyle: CSSProperties = {};
|
||||
if (color && !isPresetColor(color)) {
|
||||
statusStyle.background = color;
|
||||
}
|
||||
// <Badge status="success" />
|
||||
if (!children.length && this.hasStatus()) {
|
||||
const styleWithOffset = this.getStyleWithOffset();
|
||||
const statusTextColor = styleWithOffset && styleWithOffset.color;
|
||||
return (
|
||||
<span class={this.getBadgeClassName(prefixCls, children)} style={styleWithOffset}>
|
||||
<span class={statusCls} style={statusStyle} />
|
||||
<span style={{ color: statusTextColor }} class={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
const children = flattenChildren(slots.default?.());
|
||||
let count = getPropsSlot(slots, props, 'count');
|
||||
if (Array.isArray(count)) {
|
||||
count = count[0];
|
||||
}
|
||||
state.badgeCount = count;
|
||||
const scrollNumber = renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
|
||||
const statusText = renderStatusText(prefixCls);
|
||||
const statusCls = classNames({
|
||||
[`${prefixCls}-status-dot`]: hasStatus.value,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-status-${color}`]: isPresetColor(color),
|
||||
});
|
||||
const statusStyle: CSSProperties = {};
|
||||
if (color && !isPresetColor(color)) {
|
||||
statusStyle.background = color;
|
||||
}
|
||||
// <Badge status="success" />
|
||||
if (!children.length && hasStatus.value) {
|
||||
const styleWithOffset = getStyleWithOffset();
|
||||
const statusTextColor = styleWithOffset && styleWithOffset.color;
|
||||
return (
|
||||
<span class={getBadgeClassName(prefixCls, children)} style={styleWithOffset}>
|
||||
<span class={statusCls} style={statusStyle} />
|
||||
<span style={{ color: statusTextColor }} class={`${prefixCls}-status-text`}>
|
||||
{text}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const transitionProps = getTransitionProps(children.length ? `${prefixCls}-zoom` : '');
|
||||
|
||||
return (
|
||||
<span class={getBadgeClassName(prefixCls, children)}>
|
||||
{children}
|
||||
<Transition {...transitionProps}>{scrollNumber}</Transition>
|
||||
{statusText}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const transitionProps = getTransitionProps(children.length ? `${prefixCls}-zoom` : '');
|
||||
|
||||
return (
|
||||
<span class={this.getBadgeClassName(prefixCls, children)}>
|
||||
{children}
|
||||
<Transition {...transitionProps}>{scrollNumber}</Transition>
|
||||
{statusText}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import omit from 'omit.js';
|
||||
import { omit } from 'lodash-es';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import { CSSProperties, defineComponent, inject } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
inject,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onUpdated,
|
||||
reactive,
|
||||
watch,
|
||||
ExtractPropTypes,
|
||||
CSSProperties,
|
||||
DefineComponent,
|
||||
} from 'vue';
|
||||
|
||||
function getNumberArray(num: string | number | undefined | null) {
|
||||
return num
|
||||
|
@ -19,7 +29,7 @@ function getNumberArray(num: string | number | undefined | null) {
|
|||
: [];
|
||||
}
|
||||
|
||||
const ScrollNumberProps = {
|
||||
export const scrollNumberProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
count: PropTypes.any,
|
||||
component: PropTypes.string,
|
||||
|
@ -28,68 +38,30 @@ const ScrollNumberProps = {
|
|||
onAnimated: PropTypes.func,
|
||||
};
|
||||
|
||||
export type ScrollNumberProps = ExtractPropTypes<typeof scrollNumberProps>;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ScrollNumber',
|
||||
mixins: [BaseMixin],
|
||||
inheritAttrs: false,
|
||||
props: ScrollNumberProps,
|
||||
props: scrollNumberProps,
|
||||
emits: ['animated'],
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
lastCount: undefined,
|
||||
timeout: undefined,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
setup(props, { emit, attrs }) {
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
const state = reactive({
|
||||
animateStarted: true,
|
||||
sCount: this.count,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
count() {
|
||||
this.lastCount = this.sCount;
|
||||
this.setState({
|
||||
animateStarted: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
updated() {
|
||||
const { animateStarted, count } = this;
|
||||
if (animateStarted) {
|
||||
this.clearTimeout();
|
||||
// Let browser has time to reset the scroller before actually
|
||||
// performing the transition.
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setState(
|
||||
{
|
||||
animateStarted: false,
|
||||
sCount: count,
|
||||
},
|
||||
this.handleAnimated,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.clearTimeout();
|
||||
},
|
||||
methods: {
|
||||
clearTimeout() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = undefined;
|
||||
}
|
||||
},
|
||||
getPositionByNum(num: number, i: number) {
|
||||
const { sCount } = this;
|
||||
const currentCount = Math.abs(Number(sCount));
|
||||
const lastCount = Math.abs(Number(this.lastCount));
|
||||
const currentDigit = Math.abs(getNumberArray(sCount)[i] as number);
|
||||
const lastDigit = Math.abs(getNumberArray(this.lastCount)[i] as number);
|
||||
lastCount: undefined,
|
||||
sCount: props.count,
|
||||
|
||||
if (this.animateStarted) {
|
||||
timeout: undefined,
|
||||
});
|
||||
|
||||
const getPositionByNum = (num: number, i: number) => {
|
||||
const currentCount = Math.abs(Number(state.sCount));
|
||||
const lastCount = Math.abs(Number(state.lastCount));
|
||||
const currentDigit = Math.abs(getNumberArray(state.sCount)[i] as number);
|
||||
const lastDigit = Math.abs(getNumberArray(state.lastCount)[i] as number);
|
||||
|
||||
if (state.animateStarted) {
|
||||
return 10 + num;
|
||||
}
|
||||
// 同方向则在同一侧切换数字
|
||||
|
@ -103,12 +75,19 @@ export default defineComponent({
|
|||
return 10 + num;
|
||||
}
|
||||
return num;
|
||||
},
|
||||
handleAnimated() {
|
||||
this.$emit('animated');
|
||||
},
|
||||
};
|
||||
const handleAnimated = () => {
|
||||
emit('animated');
|
||||
};
|
||||
|
||||
renderNumberList(position: number, className: string) {
|
||||
const _clearTimeout = () => {
|
||||
if (state.timeout) {
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const renderNumberList = (position: number, className: string) => {
|
||||
const childrenToReturn = [];
|
||||
for (let i = 0; i < 30; i++) {
|
||||
childrenToReturn.push(
|
||||
|
@ -122,14 +101,14 @@ export default defineComponent({
|
|||
</p>,
|
||||
);
|
||||
}
|
||||
|
||||
return childrenToReturn;
|
||||
},
|
||||
renderCurrentNumber(prefixCls: string, num: number | string, i: number) {
|
||||
};
|
||||
|
||||
const renderCurrentNumber = (prefixCls: string, num: number | string, i: number) => {
|
||||
if (typeof num === 'number') {
|
||||
const position = this.getPositionByNum(num, i);
|
||||
const position = getPositionByNum(num, i);
|
||||
const removeTransition =
|
||||
this.animateStarted || getNumberArray(this.lastCount)[i] === undefined;
|
||||
state.animateStarted || getNumberArray(state.lastCount)[i] === undefined;
|
||||
const style = {
|
||||
transition: removeTransition ? 'none' : undefined,
|
||||
msTransform: `translateY(${-position * 100}%)`,
|
||||
|
@ -138,7 +117,7 @@ export default defineComponent({
|
|||
};
|
||||
return (
|
||||
<span class={`${prefixCls}-only`} style={style} key={i}>
|
||||
{this.renderNumberList(position, `${prefixCls}-only-unit`)}
|
||||
{renderNumberList(position, `${prefixCls}-only-unit`)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -147,57 +126,92 @@ export default defineComponent({
|
|||
{num}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
renderNumberElement(prefixCls: string) {
|
||||
const { sCount } = this;
|
||||
if (sCount && Number(sCount) % 1 === 0) {
|
||||
return getNumberArray(sCount)
|
||||
.map((num, i) => this.renderCurrentNumber(prefixCls, num, i))
|
||||
const renderNumberElement = (prefixCls: string) => {
|
||||
if (state.sCount && Number(state.sCount) % 1 === 0) {
|
||||
return getNumberArray(state.sCount)
|
||||
.map((num, i) => renderCurrentNumber(prefixCls, num, i))
|
||||
.reverse();
|
||||
}
|
||||
return sCount;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const { prefixCls: customizePrefixCls, title, component: Tag = 'sup', displayComponent } = this;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('scroll-number', customizePrefixCls);
|
||||
const { class: className, style = {} } = this.$attrs as {
|
||||
class?: string;
|
||||
style?: CSSProperties;
|
||||
return state.sCount;
|
||||
};
|
||||
if (displayComponent) {
|
||||
return cloneElement(displayComponent, {
|
||||
class: classNames(
|
||||
`${prefixCls}-custom-component`,
|
||||
displayComponent.props && displayComponent.props.class,
|
||||
),
|
||||
});
|
||||
}
|
||||
// fix https://fb.me/react-unknown-prop
|
||||
const restProps = omit({ ...this.$props, ...this.$attrs }, [
|
||||
'count',
|
||||
'onAnimated',
|
||||
'component',
|
||||
'prefixCls',
|
||||
'displayComponent',
|
||||
]);
|
||||
const tempStyle = { ...style };
|
||||
const newProps = {
|
||||
...restProps,
|
||||
title,
|
||||
style: tempStyle,
|
||||
class: classNames(prefixCls, className),
|
||||
};
|
||||
// allow specify the border
|
||||
// mock border-color by box-shadow for compatible with old usage:
|
||||
// <Badge count={4} style={{ backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9' }} />
|
||||
if (style && style.borderColor) {
|
||||
newProps.style.boxShadow = `0 0 0 1px ${style.borderColor} inset`;
|
||||
}
|
||||
|
||||
return <Tag {...newProps}>{this.renderNumberElement(prefixCls)}</Tag>;
|
||||
watch(
|
||||
() => props.count,
|
||||
() => {
|
||||
state.lastCount = state.sCount;
|
||||
state.animateStarted = true;
|
||||
},
|
||||
);
|
||||
|
||||
onUpdated(() => {
|
||||
if (state.animateStarted) {
|
||||
_clearTimeout();
|
||||
// Let browser has time to reset the scroller before actually
|
||||
// performing the transition.
|
||||
state.timeout = setTimeout(() => {
|
||||
state.animateStarted = false;
|
||||
state.sCount = props.count;
|
||||
nextTick(() => {
|
||||
handleAnimated();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
_clearTimeout();
|
||||
});
|
||||
|
||||
// configProvider: inject('configProvider', defaultConfigProvider),
|
||||
// lastCount: undefined,
|
||||
// timeout: undefined,
|
||||
|
||||
return () => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
title,
|
||||
component: Tag = ('sup' as unknown) as DefineComponent,
|
||||
displayComponent,
|
||||
} = props;
|
||||
const getPrefixCls = configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('scroll-number', customizePrefixCls);
|
||||
const { class: className, style = {} } = attrs as {
|
||||
class?: string;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
if (displayComponent) {
|
||||
return cloneElement(displayComponent, {
|
||||
class: classNames(
|
||||
`${prefixCls}-custom-component`,
|
||||
displayComponent.props && displayComponent.props.class,
|
||||
),
|
||||
});
|
||||
}
|
||||
// fix https://fb.me/react-unknown-prop
|
||||
const restProps = omit({ ...props, ...attrs }, [
|
||||
'count',
|
||||
'onAnimated',
|
||||
'component',
|
||||
'prefixCls',
|
||||
'displayComponent',
|
||||
]);
|
||||
const tempStyle = { ...style };
|
||||
const newProps = {
|
||||
...restProps,
|
||||
title,
|
||||
style: tempStyle,
|
||||
class: classNames(prefixCls, className),
|
||||
};
|
||||
// allow specify the border
|
||||
// mock border-color by box-shadow for compatible with old usage:
|
||||
// <Badge count={4} style={{ backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9' }} />
|
||||
if (style && style.borderColor) {
|
||||
newProps.style.boxShadow = `0 0 0 1px ${style.borderColor} inset`;
|
||||
}
|
||||
|
||||
return <Tag {...newProps}>{renderNumberElement(prefixCls)}</Tag>;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -31,6 +31,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
&-count-sm {
|
||||
min-width: @badge-height-sm;
|
||||
height: @badge-height-sm;
|
||||
padding: 0;
|
||||
font-size: @badge-font-size-sm;
|
||||
line-height: @badge-height-sm;
|
||||
border-radius: (@badge-height-sm / 2);
|
||||
}
|
||||
|
||||
&-multiple-words {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
|
|
@ -581,11 +581,14 @@
|
|||
// Badge
|
||||
// ---
|
||||
@badge-height: 20px;
|
||||
@badge-height-sm: 14px;
|
||||
@badge-dot-size: 6px;
|
||||
@badge-font-size: @font-size-sm;
|
||||
@badge-font-size-sm: @font-size-sm;
|
||||
@badge-font-weight: normal;
|
||||
@badge-status-size: 6px;
|
||||
@badge-text-color: @component-background;
|
||||
@badge-color: @highlight-color;
|
||||
|
||||
// Rate
|
||||
// ---
|
||||
|
|
Loading…
Reference in New Issue