refactor(tag): less to cssinjs (#6227)
parent
9b5a07220b
commit
a205615af9
|
@ -3,7 +3,7 @@
|
|||
import './radio/style';
|
||||
import './checkbox/style';
|
||||
// import './grid/style';
|
||||
import './tag/style';
|
||||
// import './tag/style';
|
||||
import './rate/style';
|
||||
import './pagination/style';
|
||||
// import './avatar/style';
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { ExtractPropTypes, PropType } from 'vue';
|
|||
import { defineComponent, computed } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import useStyle from './style';
|
||||
|
||||
const checkableTagProps = () => ({
|
||||
prefixCls: String,
|
||||
|
@ -19,10 +20,14 @@ export type CheckableTagProps = Partial<ExtractPropTypes<ReturnType<typeof check
|
|||
const CheckableTag = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
name: 'ACheckableTag',
|
||||
inheritAttrs: false,
|
||||
props: checkableTagProps(),
|
||||
// emits: ['update:checked', 'change', 'click'],
|
||||
setup(props, { slots, emit }) {
|
||||
setup(props, { slots, emit, attrs }) {
|
||||
const { prefixCls } = useConfigInject('tag', props);
|
||||
// Style
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
const { checked } = props;
|
||||
emit('update:checked', !checked);
|
||||
|
@ -31,17 +36,17 @@ const CheckableTag = defineComponent({
|
|||
};
|
||||
|
||||
const cls = computed(() =>
|
||||
classNames(prefixCls.value, {
|
||||
classNames(prefixCls.value, hashId.value, {
|
||||
[`${prefixCls.value}-checkable`]: true,
|
||||
[`${prefixCls.value}-checkable-checked`]: props.checked,
|
||||
}),
|
||||
);
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<span class={cls.value} onClick={handleClick}>
|
||||
return wrapSSR(
|
||||
<span {...attrs} class={cls.value} onClick={handleClick}>
|
||||
{slots.default?.()}
|
||||
</span>
|
||||
</span>,
|
||||
);
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<docs>
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 控制关闭状态
|
||||
en-US: Controlled
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
通过 `visible` 属性控制关闭状态。
|
||||
|
||||
## en-US
|
||||
|
||||
By using the `visible` prop, you can control the close state of Tag.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-tag v-model:visible="visible" closable>Movies</a-tag>
|
||||
<br />
|
||||
<a-button size="small" @click="visible = !visible">Toggle</a-button>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return {
|
||||
visible: ref(false),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -4,7 +4,6 @@
|
|||
<Checkable />
|
||||
<Colorful />
|
||||
<Control />
|
||||
<Controlled />
|
||||
<HotTags />
|
||||
<Icon />
|
||||
<Status />
|
||||
|
@ -16,7 +15,6 @@ import Basic from './basic.vue';
|
|||
import Checkable from './checkable.vue';
|
||||
import Colorful from './colorful.vue';
|
||||
import Control from './control.vue';
|
||||
import Controlled from './controlled.vue';
|
||||
import HotTags from './hot-tags.vue';
|
||||
import Icon from './icon.vue';
|
||||
import Status from './status.vue';
|
||||
|
@ -32,7 +30,6 @@ export default defineComponent({
|
|||
Checkable,
|
||||
Colorful,
|
||||
Control,
|
||||
Controlled,
|
||||
HotTags,
|
||||
Icon,
|
||||
Status,
|
||||
|
|
|
@ -16,13 +16,12 @@ Tag for categorizing or markup.
|
|||
|
||||
### Tag
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| ---------------- | -------------------------------- | ------------- | ------- | ------- |
|
||||
| closable | Whether the Tag can be closed | boolean | `false` | |
|
||||
| closeIcon | Custom close icon | VNode \| slot | - | 2.0.0 |
|
||||
| color | Color of the Tag | string | - | |
|
||||
| icon | Set the icon of tag | VNode \| slot | - | 2.0.0 |
|
||||
| visible(v-model) | Whether the Tag is closed or not | boolean | `true` | |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --------- | ----------------------------- | ------------- | ------- | ------- |
|
||||
| closable | Whether the Tag can be closed | boolean | `false` | |
|
||||
| closeIcon | Custom close icon | VNode \| slot | - | 2.0.0 |
|
||||
| color | Color of the Tag | string | - | |
|
||||
| icon | Set the icon of tag | VNode \| slot | - | 2.0.0 |
|
||||
|
||||
### Tag Events
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ import { isPresetColor, isPresetStatusColor } from '../_util/colors';
|
|||
import type { LiteralUnion } from '../_util/type';
|
||||
import CheckableTag from './CheckableTag';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import warning from '../_util/warning';
|
||||
|
||||
import useStyle from './style';
|
||||
|
||||
export const tagProps = () => ({
|
||||
prefixCls: String,
|
||||
|
@ -17,6 +20,7 @@ export const tagProps = () => ({
|
|||
},
|
||||
closable: { type: Boolean, default: false },
|
||||
closeIcon: PropTypes.any,
|
||||
/** @deprecated `visible` will be removed in next major version. */
|
||||
visible: { type: Boolean, default: undefined },
|
||||
onClose: {
|
||||
type: Function as PropType<(e: MouseEvent) => void>,
|
||||
|
@ -30,14 +34,26 @@ export type TagProps = HTMLAttributes & Partial<ExtractPropTypes<ReturnType<type
|
|||
const Tag = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
name: 'ATag',
|
||||
inheritAttrs: false,
|
||||
props: tagProps(),
|
||||
// emits: ['update:visible', 'close'],
|
||||
slots: ['closeIcon', 'icon'],
|
||||
setup(props: TagProps, { slots, emit, attrs }) {
|
||||
const { prefixCls, direction } = useConfigInject('tag', props);
|
||||
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
|
||||
const visible = ref(true);
|
||||
|
||||
// Warning for deprecated usage
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(
|
||||
!('visible' in props),
|
||||
'Tag',
|
||||
'`visible` is deprecated, please use `<Tag v-show="visible" />` instead.',
|
||||
);
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.visible !== undefined) {
|
||||
visible.value = props.visible!;
|
||||
|
@ -70,7 +86,7 @@ const Tag = defineComponent({
|
|||
);
|
||||
|
||||
const tagClassName = computed(() =>
|
||||
classNames(prefixCls.value, {
|
||||
classNames(prefixCls.value, hashId.value, {
|
||||
[`${prefixCls.value}-${props.color}`]: isInternalColor.value,
|
||||
[`${prefixCls.value}-has-color`]: props.color && !isInternalColor.value,
|
||||
[`${prefixCls.value}-hidden`]: !visible.value,
|
||||
|
@ -117,13 +133,13 @@ const Tag = defineComponent({
|
|||
const isNeedWave = 'onClick' in attrs;
|
||||
|
||||
const tagNode = (
|
||||
<span class={tagClassName.value} style={tagStyle}>
|
||||
<span {...attrs} class={tagClassName.value} style={tagStyle}>
|
||||
{kids}
|
||||
{renderCloseIcon()}
|
||||
</span>
|
||||
);
|
||||
|
||||
return isNeedWave ? <Wave>{tagNode}</Wave> : tagNode;
|
||||
return wrapSSR(isNeedWave ? <Wave>{tagNode}</Wave> : tagNode);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -17,13 +17,12 @@ cover: https://gw.alipayobjects.com/zos/alicdn/cH1BOLfxC/Tag.svg
|
|||
|
||||
### Tag
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ---------------- | ---------------- | ------------- | ------ | ----- |
|
||||
| closable | 标签是否可以关闭 | boolean | false | |
|
||||
| closeIcon | 自定义关闭按钮 | VNode \| slot | - | 2.0.0 |
|
||||
| color | 标签色 | string | - | |
|
||||
| icon | 设置图标 | VNode \| slot | - | 2.0.0 |
|
||||
| visible(v-model) | 是否显示标签 | boolean | `true` | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------- | ---------------- | ------------- | ------ | ----- |
|
||||
| closable | 标签是否可以关闭 | boolean | false | |
|
||||
| closeIcon | 自定义关闭按钮 | VNode \| slot | - | 2.0.0 |
|
||||
| color | 标签色 | string | - | |
|
||||
| icon | 设置图标 | VNode \| slot | - | 2.0.0 |
|
||||
|
||||
### 事件
|
||||
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@tag-prefix-cls: ~'@{ant-prefix}-tag';
|
||||
|
||||
.@{tag-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
display: inline-block;
|
||||
height: auto;
|
||||
margin-right: 8px;
|
||||
padding: 0 7px;
|
||||
font-size: @tag-font-size;
|
||||
line-height: @tag-line-height;
|
||||
white-space: nowrap;
|
||||
background: @tag-default-bg;
|
||||
border: @border-width-base @border-style-base @border-color-base;
|
||||
border-radius: @tag-border-radius;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
|
||||
&,
|
||||
a,
|
||||
a:hover {
|
||||
color: @tag-default-color;
|
||||
}
|
||||
|
||||
> a:first-child:last-child {
|
||||
display: inline-block;
|
||||
margin: 0 -8px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
&-close-icon {
|
||||
margin-left: 3px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: @heading-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-has-color {
|
||||
border-color: transparent;
|
||||
&,
|
||||
a,
|
||||
a:hover,
|
||||
.@{iconfont-css-prefix}-close,
|
||||
.@{iconfont-css-prefix}-close:hover {
|
||||
color: @text-color-inverse;
|
||||
}
|
||||
}
|
||||
|
||||
&-checkable {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(&-checked):hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&-checked {
|
||||
color: @text-color-inverse;
|
||||
}
|
||||
|
||||
&-checked {
|
||||
background-color: @primary-6;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: @primary-7;
|
||||
}
|
||||
}
|
||||
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// mixin to iterate over colors and create CSS class for each one
|
||||
.make-color-classes(@i: length(@preset-colors)) when (@i > 0) {
|
||||
.make-color-classes(@i - 1);
|
||||
@color: extract(@preset-colors, @i);
|
||||
@lightColor: '@{color}-1';
|
||||
@lightBorderColor: '@{color}-3';
|
||||
@darkColor: '@{color}-6';
|
||||
@textColor: '@{color}-7';
|
||||
&-@{color} {
|
||||
color: @@textColor;
|
||||
background: @@lightColor;
|
||||
border-color: @@lightBorderColor;
|
||||
}
|
||||
&-@{color}-inverse {
|
||||
color: @text-color-inverse;
|
||||
background: @@darkColor;
|
||||
border-color: @@darkColor;
|
||||
}
|
||||
}
|
||||
|
||||
.make-status-color-classes(@status, @cssVariableType) {
|
||||
@bgColor: '@{cssVariableType}-color-deprecated-bg';
|
||||
@borderColor: '@{cssVariableType}-color-deprecated-border';
|
||||
@textColor: '@{cssVariableType}-color';
|
||||
&-@{status} {
|
||||
color: @@textColor;
|
||||
background: @@bgColor;
|
||||
border-color: @@borderColor;
|
||||
}
|
||||
}
|
||||
|
||||
.make-color-classes();
|
||||
|
||||
.make-status-color-classes(success, success);
|
||||
.make-status-color-classes(processing, info);
|
||||
.make-status-color-classes(error, error);
|
||||
.make-status-color-classes(warning, warning);
|
||||
|
||||
// To ensure that a space will be placed between character and `Icon`.
|
||||
> .@{iconfont-css-prefix} + span,
|
||||
> span + .@{iconfont-css-prefix} {
|
||||
margin-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
@import './rtl';
|
|
@ -0,0 +1,171 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { genPresetColor, resetComponent } from '../../_style';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { capitalize } from '../../_util/util';
|
||||
|
||||
export interface ComponentToken {}
|
||||
|
||||
interface TagToken extends FullToken<'Tag'> {
|
||||
tagFontSize: number;
|
||||
tagLineHeight: CSSProperties['lineHeight'];
|
||||
tagDefaultBg: string;
|
||||
tagDefaultColor: string;
|
||||
tagIconSize: number;
|
||||
tagPaddingHorizontal: number;
|
||||
}
|
||||
|
||||
// ============================== Styles ==============================
|
||||
|
||||
type CssVariableType = 'Success' | 'Info' | 'Error' | 'Warning';
|
||||
|
||||
const genTagStatusStyle = (
|
||||
token: TagToken,
|
||||
status: 'success' | 'processing' | 'error' | 'warning',
|
||||
cssVariableType: CssVariableType,
|
||||
): CSSObject => {
|
||||
const capitalizedCssVariableType = capitalize(cssVariableType);
|
||||
return {
|
||||
[`${token.componentCls}-${status}`]: {
|
||||
color: token[`color${cssVariableType}`],
|
||||
background: token[`color${capitalizedCssVariableType}Bg`],
|
||||
borderColor: token[`color${capitalizedCssVariableType}Border`],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const genPresetStyle = (token: TagToken) =>
|
||||
genPresetColor(token, (colorKey, { textColor, lightBorderColor, lightColor, darkColor }) => ({
|
||||
[`${token.componentCls}-${colorKey}`]: {
|
||||
color: textColor,
|
||||
background: lightColor,
|
||||
borderColor: lightBorderColor,
|
||||
|
||||
// Inverse color
|
||||
'&-inverse': {
|
||||
color: token.colorTextLightSolid,
|
||||
background: darkColor,
|
||||
borderColor: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const genBaseStyle = (token: TagToken): CSSObject => {
|
||||
const { paddingXXS, lineWidth, tagPaddingHorizontal, componentCls } = token;
|
||||
const paddingInline = tagPaddingHorizontal - lineWidth;
|
||||
const iconMarginInline = paddingXXS - lineWidth;
|
||||
|
||||
return {
|
||||
// Result
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
display: 'inline-block',
|
||||
height: 'auto',
|
||||
marginInlineEnd: token.marginXS,
|
||||
paddingInline,
|
||||
fontSize: token.tagFontSize,
|
||||
lineHeight: `${token.tagLineHeight}px`,
|
||||
whiteSpace: 'nowrap',
|
||||
background: token.tagDefaultBg,
|
||||
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
|
||||
borderRadius: token.borderRadiusSM,
|
||||
opacity: 1,
|
||||
transition: `all ${token.motionDurationMid}`,
|
||||
textAlign: 'start',
|
||||
|
||||
// RTL
|
||||
[`&${componentCls}-rtl`]: {
|
||||
direction: 'rtl',
|
||||
},
|
||||
|
||||
'&, a, a:hover': {
|
||||
color: token.tagDefaultColor,
|
||||
},
|
||||
|
||||
[`${componentCls}-close-icon`]: {
|
||||
marginInlineStart: iconMarginInline,
|
||||
color: token.colorTextDescription,
|
||||
fontSize: token.tagIconSize,
|
||||
cursor: 'pointer',
|
||||
transition: `all ${token.motionDurationMid}`,
|
||||
|
||||
'&:hover': {
|
||||
color: token.colorTextHeading,
|
||||
},
|
||||
},
|
||||
|
||||
[`&${componentCls}-has-color`]: {
|
||||
borderColor: 'transparent',
|
||||
|
||||
[`&, a, a:hover, ${token.iconCls}-close, ${token.iconCls}-close:hover`]: {
|
||||
color: token.colorTextLightSolid,
|
||||
},
|
||||
},
|
||||
|
||||
[`&-checkable`]: {
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: 'transparent',
|
||||
cursor: 'pointer',
|
||||
|
||||
[`&:not(${componentCls}-checkable-checked):hover`]: {
|
||||
color: token.colorPrimary,
|
||||
backgroundColor: token.colorFillSecondary,
|
||||
},
|
||||
|
||||
'&:active, &-checked': {
|
||||
color: token.colorTextLightSolid,
|
||||
},
|
||||
|
||||
'&-checked': {
|
||||
backgroundColor: token.colorPrimary,
|
||||
'&:hover': {
|
||||
backgroundColor: token.colorPrimaryHover,
|
||||
},
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
backgroundColor: token.colorPrimaryActive,
|
||||
},
|
||||
},
|
||||
|
||||
[`&-hidden`]: {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
// To ensure that a space will be placed between character and `Icon`.
|
||||
[`> ${token.iconCls} + span, > span + ${token.iconCls}`]: {
|
||||
marginInlineStart: paddingInline,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook('Tag', token => {
|
||||
const { fontSize, lineHeight, lineWidth, fontSizeIcon } = token;
|
||||
const tagHeight = Math.round(fontSize * lineHeight);
|
||||
|
||||
const tagFontSize = token.fontSizeSM;
|
||||
const tagLineHeight = tagHeight - lineWidth * 2;
|
||||
const tagDefaultBg = token.colorFillAlter;
|
||||
const tagDefaultColor = token.colorText;
|
||||
|
||||
const tagToken = mergeToken<TagToken>(token, {
|
||||
tagFontSize,
|
||||
tagLineHeight,
|
||||
tagDefaultBg,
|
||||
tagDefaultColor,
|
||||
tagIconSize: fontSizeIcon - 2 * lineWidth, // Tag icon is much more smaller
|
||||
tagPaddingHorizontal: 8, // Fixed padding.
|
||||
});
|
||||
|
||||
return [
|
||||
genBaseStyle(tagToken),
|
||||
genPresetStyle(tagToken),
|
||||
genTagStatusStyle(tagToken, 'success', 'Success'),
|
||||
genTagStatusStyle(tagToken, 'processing', 'Info'),
|
||||
genTagStatusStyle(tagToken, 'error', 'Error'),
|
||||
genTagStatusStyle(tagToken, 'warning', 'Warning'),
|
||||
];
|
||||
});
|
|
@ -1,2 +0,0 @@
|
|||
import '../../style/index.less';
|
||||
import './index.less';
|
|
@ -1,28 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@tag-prefix-cls: ~'@{ant-prefix}-tag';
|
||||
|
||||
.@{tag-prefix-cls} {
|
||||
&&-rtl {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-close-icon {
|
||||
.@{tag-prefix-cls}-rtl & {
|
||||
margin-right: 3px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix} + span,
|
||||
> span + .@{iconfont-css-prefix} {
|
||||
.@{tag-prefix-cls}-rtl& {
|
||||
margin-right: 7px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ import type { ComponentToken as SpinComponentToken } from '../../spin/style';
|
|||
// import type { ComponentToken as StepsComponentToken } from '../../steps/style';
|
||||
// import type { ComponentToken as TableComponentToken } from '../../table/style';
|
||||
// import type { ComponentToken as TabsComponentToken } from '../../tabs/style';
|
||||
// import type { ComponentToken as TagComponentToken } from '../../tag/style';
|
||||
import type { ComponentToken as TagComponentToken } from '../../tag/style';
|
||||
// import type { ComponentToken as TimelineComponentToken } from '../../timeline/style';
|
||||
import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style';
|
||||
// import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
|
||||
|
@ -93,7 +93,7 @@ export interface ComponentTokenMap {
|
|||
Spin?: SpinComponentToken;
|
||||
Statistic?: {};
|
||||
Switch?: {};
|
||||
// Tag?: TagComponentToken;
|
||||
Tag?: TagComponentToken;
|
||||
Tree?: {};
|
||||
TreeSelect?: {};
|
||||
// Typography?: TypographyComponentToken;
|
||||
|
|
Loading…
Reference in New Issue