refactor:typography (#6244)

* refactor:typography

* fix return

* fix import type
pull/6246/head^2
果冻橙 2023-02-12 09:56:57 +08:00 committed by GitHub
parent 23b81b0e17
commit 82c4c8f0d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 450 additions and 408 deletions

View File

@ -60,5 +60,5 @@ import './result/style';
import './form/style';
// import './space/style';
import './image/style';
import './typography/style';
// import './typography/style';
// import './color-picker/style';

View File

@ -43,7 +43,7 @@ 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';
// import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
// import type { ComponentToken as UploadComponentToken } from '../../upload/style';
// import type { ComponentToken as TourComponentToken } from '../../tour/style';
// import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
@ -98,7 +98,7 @@ export interface ComponentTokenMap {
Tag?: TagComponentToken;
Tree?: {};
TreeSelect?: {};
// Typography?: TypographyComponentToken;
Typography?: TypographyComponentToken;
// Timeline?: TimelineComponentToken;
// Transfer?: TransferComponentToken;
// Tabs?: TabsComponentToken;

View File

@ -2,10 +2,14 @@ import KeyCode from '../_util/KeyCode';
import TextArea from '../input/TextArea';
import EnterOutlined from '@ant-design/icons-vue/EnterOutlined';
import type { ExtractPropTypes, PropType } from 'vue';
import { defineComponent, ref, reactive, watch, onMounted, computed } from 'vue';
import { defineComponent, ref, reactive, watch, onMounted, toRefs } from 'vue';
import type { Direction } from '../config-provider';
import type { ChangeEventHandler } from '../_util/EventInterface';
import type { AutoSizeType } from '../input/inputProps';
import classNames from '../_util/classNames';
// CSSINJS
import useStyle from './style';
const editableProps = () => ({
prefixCls: String,
@ -24,9 +28,11 @@ export type EditableProps = Partial<ExtractPropTypes<ReturnType<typeof editableP
const Editable = defineComponent({
compatConfig: { MODE: 3 },
name: 'Editable',
inheritAttrs: false,
props: editableProps(),
// emits: ['save', 'cancel', 'end', 'change'],
setup(props, { emit, slots }) {
setup(props, { emit, slots, attrs }) {
const { prefixCls } = toRefs(props);
const state = reactive({
current: props.value || '',
lastKeyCode: undefined,
@ -109,14 +115,24 @@ const Editable = defineComponent({
function confirmChange() {
emit('save', state.current.trim());
}
const textAreaClassName = computed(() => ({
[`${props.prefixCls}`]: true,
[`${props.prefixCls}-edit-content`]: true,
[`${props.prefixCls}-rtl`]: props.direction === 'rtl',
[props.component ? `${props.prefixCls}-${props.component}` : '']: true,
}));
return () => (
<div class={textAreaClassName.value}>
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
return () => {
const textAreaClassName = classNames(
{
[`${prefixCls.value}`]: true,
[`${prefixCls.value}-edit-content`]: true,
[`${prefixCls.value}-rtl`]: props.direction === 'rtl',
[props.component ? `${prefixCls.value}-${props.component}` : '']: true,
},
attrs.class,
hashId.value,
);
return wrapSSR(
<div {...attrs} class={textAreaClassName}>
<TextArea
ref={saveTextAreaRef}
maxlength={props.maxlength}
@ -135,8 +151,9 @@ const Editable = defineComponent({
) : (
<EnterOutlined class={`${props.prefixCls}-edit-content-confirm`} />
)}
</div>
</div>,
);
};
},
});

View File

@ -4,6 +4,9 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
import classNames from '../_util/classNames';
import type { Direction } from '../config-provider';
// CSSINJS
import useStyle from './style';
export interface TypographyProps extends HTMLAttributes {
direction?: Direction;
prefixCls?: string;
@ -24,6 +27,10 @@ const Typography = defineComponent<InternalTypographyProps>({
props: typographyProps() as any,
setup(props, { slots, attrs }) {
const { prefixCls, direction } = useConfigInject('typography', props);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
return () => {
const {
prefixCls: _prefixCls,
@ -32,17 +39,18 @@ const Typography = defineComponent<InternalTypographyProps>({
component: Component = 'article' as any,
...restProps
} = { ...props, ...attrs };
return (
return wrapSSR(
<Component
class={classNames(
prefixCls.value,
{ [`${prefixCls.value}-rtl`]: direction.value === 'rtl' },
attrs.class,
hashId.value,
)}
{...restProps}
>
{slots.default?.()}
</Component>
</Component>,
);
};
},

View File

@ -1,314 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@typography-prefix-cls: ~'@{ant-prefix}-typography';
// =============== Basic ===============
.@{typography-prefix-cls} {
color: @text-color;
overflow-wrap: break-word;
&&-secondary {
color: @text-color-secondary;
}
&&-success {
color: @success-color;
}
&&-warning {
color: @warning-color;
}
&&-danger {
color: @error-color;
a&:active,
a&:focus {
color: @error-color-active;
}
a&:hover {
color: @error-color-hover;
}
}
&&-disabled {
color: @disabled-color;
cursor: not-allowed;
user-select: none;
}
// Tag
div&,
p {
.typography-paragraph();
}
h1&,
div&-h1,
div&-h1 > textarea,
h1 {
.typography-title-1();
}
h2&,
div&-h2,
div&-h2 > textarea,
h2 {
.typography-title-2();
}
h3&,
div&-h3,
div&-h3 > textarea,
h3 {
.typography-title-3();
}
h4&,
div&-h4,
div&-h4 > textarea,
h4 {
.typography-title-4();
}
h5&,
div&-h5,
div&-h5 > textarea,
h5 {
.typography-title-5();
}
h1&,
h2&,
h3&,
h4&,
h5& {
.@{typography-prefix-cls} + & {
margin-top: @typography-title-margin-top;
}
}
div,
ul,
li,
p,
h1,
h2,
h3,
h4,
h5 {
+ h1,
+ h2,
+ h3,
+ h4,
+ h5 {
margin-top: @typography-title-margin-top;
}
}
a&-ellipsis,
span&-ellipsis {
display: inline-block;
max-width: 100%;
}
a&,
a {
.operation-unit();
text-decoration: @link-decoration;
&:active,
&:hover {
text-decoration: @link-hover-decoration;
}
&[disabled],
&.@{typography-prefix-cls}-disabled {
color: @disabled-color;
cursor: not-allowed;
&:active,
&:hover {
color: @disabled-color;
}
&:active {
pointer-events: none;
}
}
}
code {
margin: 0 0.2em;
padding: 0.2em 0.4em 0.1em;
font-size: 85%;
background: rgba(150, 150, 150, 0.1);
border: 1px solid rgba(100, 100, 100, 0.2);
border-radius: 3px;
}
kbd {
margin: 0 0.2em;
padding: 0.15em 0.4em 0.1em;
font-size: 90%;
background: rgba(150, 150, 150, 0.06);
border: 1px solid rgba(100, 100, 100, 0.2);
border-bottom-width: 2px;
border-radius: 3px;
}
mark {
padding: 0;
background-color: @gold-3;
}
u,
ins {
text-decoration: underline;
text-decoration-skip-ink: auto;
}
s,
del {
text-decoration: line-through;
}
strong {
font-weight: 600;
}
// Operation
&-expand,
&-edit,
&-copy {
.operation-unit();
margin-left: 4px;
}
&-copy-success {
&,
&:hover,
&:focus {
color: @success-color;
}
}
// Text input area
&-edit-content {
position: relative;
div& {
left: -@input-padding-horizontal - 1px;
margin-top: -@input-padding-vertical-base - 1px;
margin-bottom: calc(1em - @input-padding-vertical-base - 1px);
}
&-confirm {
position: absolute;
right: 10px;
bottom: 8px;
color: @text-color-secondary;
// default style
font-weight: normal;
font-size: @font-size-base;
font-style: normal;
pointer-events: none;
}
// Fix Editable Textarea flash in Firefox
textarea {
// https://stackoverflow.com/a/7695964/3040605
height: 1em;
margin: 0 !important;
/* stylelint-disable-next-line property-no-vendor-prefix */
-moz-transition: none;
}
}
// list
ul,
ol {
margin: 0 0 1em;
padding: 0;
li {
margin: 0 0 0 20px;
padding: 0 0 0 4px;
}
}
ul {
list-style-type: circle;
ul {
list-style-type: disc;
}
}
ol {
list-style-type: decimal;
}
// pre & block
pre,
blockquote {
margin: 1em 0;
}
pre {
padding: 0.4em 0.6em;
white-space: pre-wrap;
word-wrap: break-word;
background: rgba(150, 150, 150, 0.1);
border: 1px solid rgba(100, 100, 100, 0.2);
border-radius: 3px;
// Compatible for marked
code {
display: inline;
margin: 0;
padding: 0;
font-size: inherit;
font-family: inherit;
background: transparent;
border: 0;
}
}
blockquote {
padding: 0 0 0 0.6em;
border-left: 4px solid rgba(100, 100, 100, 0.2);
opacity: 0.85;
}
// ============ Ellipsis ============
&-single-line {
white-space: nowrap;
}
&-ellipsis-single-line {
overflow: hidden;
text-overflow: ellipsis;
// https://blog.csdn.net/iefreer/article/details/50421025
a&,
span& {
vertical-align: bottom;
}
}
&-ellipsis-multiple-line {
/* stylelint-disable-next-line value-no-vendor-prefix */
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 3;
/*! autoprefixer: ignore next */
-webkit-box-orient: vertical;
}
}
@import './rtl';

View File

@ -1,6 +1,128 @@
import '../../style/index.less';
import './index.less';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook } from '../../theme/internal';
import {
getCopiableStyles,
getEditableStyles,
getEllipsisStyles,
getLinkStyles,
getResetStyles,
getTitleStyles,
} from './mixins';
import { operationUnit } from '../../_style';
// style dependencies
import '../../tooltip/style';
import '../../input/style';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
sizeMarginHeadingVerticalStart: number | string;
sizeMarginHeadingVerticalEnd: number | string;
}
export type TypographyToken = FullToken<'Typography'>;
const genTypographyStyle: GenerateStyle<TypographyToken> = token => {
const { componentCls, sizeMarginHeadingVerticalStart } = token;
return {
[componentCls]: {
color: token.colorText,
wordBreak: 'break-word',
lineHeight: token.lineHeight,
[`&${componentCls}-secondary`]: {
color: token.colorTextDescription,
},
[`&${componentCls}-success`]: {
color: token.colorSuccess,
},
[`&${componentCls}-warning`]: {
color: token.colorWarning,
},
[`&${componentCls}-danger`]: {
color: token.colorError,
'a&:active, a&:focus': {
color: token.colorErrorActive,
},
'a&:hover': {
color: token.colorErrorHover,
},
},
[`&${componentCls}-disabled`]: {
color: token.colorTextDisabled,
cursor: 'not-allowed',
userSelect: 'none',
},
[`
div&,
p
`]: {
marginBottom: '1em',
},
...getTitleStyles(token),
[`
& + h1${componentCls},
& + h2${componentCls},
& + h3${componentCls},
& + h4${componentCls},
& + h5${componentCls}
`]: {
marginTop: sizeMarginHeadingVerticalStart,
},
[`
div,
ul,
li,
p,
h1,
h2,
h3,
h4,
h5`]: {
[`
+ h1,
+ h2,
+ h3,
+ h4,
+ h5
`]: {
marginTop: sizeMarginHeadingVerticalStart,
},
},
...getResetStyles(),
...getLinkStyles(token),
// Operation
[`
${componentCls}-expand,
${componentCls}-edit,
${componentCls}-copy
`]: {
...operationUnit(token),
marginInlineStart: token.marginXXS,
},
...getEditableStyles(token),
...getCopiableStyles(token),
...getEllipsisStyles(),
'&-rtl': {
direction: 'rtl',
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Typography', token => [genTypographyStyle(token)], {
sizeMarginHeadingVerticalStart: '1.2em',
sizeMarginHeadingVerticalEnd: '0.5em',
});

View File

@ -0,0 +1,263 @@
/*
.typography-title(@fontSize; @fontWeight; @lineHeight; @headingColor; @headingMarginBottom;) {
margin-bottom: @headingMarginBottom;
color: @headingColor;
font-weight: @fontWeight;
fontSize: @fontSize;
line-height: @lineHeight;
}
*/
import { gold } from '@ant-design/colors';
import type { CSSObject } from '../../_util/cssinjs';
import type { TypographyToken } from '.';
import { initInputToken } from '../../input/style';
import type { GenerateStyle } from '../../theme/internal';
import { operationUnit } from '../../_style';
// eslint-disable-next-line import/prefer-default-export
const getTitleStyle = (
fontSize: number,
lineHeight: number,
color: string,
token: TypographyToken,
) => {
const { sizeMarginHeadingVerticalEnd, fontWeightStrong } = token;
return {
marginBottom: sizeMarginHeadingVerticalEnd,
color,
fontWeight: fontWeightStrong,
fontSize,
lineHeight,
};
};
// eslint-disable-next-line import/prefer-default-export
export const getTitleStyles: GenerateStyle<TypographyToken, CSSObject> = token => {
const headings = [1, 2, 3, 4, 5] as const;
const styles = {} as CSSObject;
headings.forEach(headingLevel => {
styles[
`
h${headingLevel}&,
div&-h${headingLevel},
div&-h${headingLevel} > textarea,
h${headingLevel}
`
] = getTitleStyle(
token[`fontSizeHeading${headingLevel}`],
token[`lineHeightHeading${headingLevel}`],
token.colorTextHeading,
token,
);
});
return styles;
};
export const getLinkStyles: GenerateStyle<TypographyToken, CSSObject> = token => {
const { componentCls } = token;
return {
'a&, a': {
...operationUnit(token),
textDecoration: token.linkDecoration,
'&:active, &:hover': {
textDecoration: token.linkHoverDecoration,
},
[`&[disabled], &${componentCls}-disabled`]: {
color: token.colorTextDisabled,
cursor: 'not-allowed',
'&:active, &:hover': {
color: token.colorTextDisabled,
},
'&:active': {
pointerEvents: 'none',
},
},
},
};
};
export const getResetStyles = (): CSSObject => ({
code: {
margin: '0 0.2em',
paddingInline: '0.4em',
paddingBlock: '0.2em 0.1em',
fontSize: '85%',
background: 'rgba(150, 150, 150, 0.1)',
border: '1px solid rgba(100, 100, 100, 0.2)',
borderRadius: 3,
},
kbd: {
margin: '0 0.2em',
paddingInline: '0.4em',
paddingBlock: '0.15em 0.1em',
fontSize: '90%',
background: 'rgba(150, 150, 150, 0.06)',
border: '1px solid rgba(100, 100, 100, 0.2)',
borderBottomWidth: 2,
borderRadius: 3,
},
mark: {
padding: 0,
// FIXME hardcode in v4
backgroundColor: gold[2],
},
'u, ins': {
textDecoration: 'underline',
textDecorationSkipInk: 'auto',
},
's, del': {
textDecoration: 'line-through',
},
strong: {
fontWeight: 600,
},
// list
'ul, ol': {
marginInline: 0,
marginBlock: '0 1em',
padding: 0,
li: {
marginInline: '20px 0',
marginBlock: 0,
paddingInline: '4px 0',
paddingBlock: 0,
},
},
ul: {
listStyleType: 'circle',
ul: {
listStyleType: 'disc',
},
},
ol: {
listStyleType: 'decimal',
},
// pre & block
'pre, blockquote': {
margin: '1em 0',
},
pre: {
padding: '0.4em 0.6em',
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
background: 'rgba(150, 150, 150, 0.1)',
border: '1px solid rgba(100, 100, 100, 0.2)',
borderRadius: 3,
// Compatible for marked
code: {
display: 'inline',
margin: 0,
padding: 0,
fontSize: 'inherit',
fontFamily: 'inherit',
background: 'transparent',
border: 0,
},
},
blockquote: {
paddingInline: '0.6em 0',
paddingBlock: 0,
borderInlineStart: '4px solid rgba(100, 100, 100, 0.2)',
opacity: 0.85,
},
});
export const getEditableStyles: GenerateStyle<TypographyToken, CSSObject> = token => {
const { componentCls } = token;
const inputToken = initInputToken(token);
const inputShift = inputToken.inputPaddingVertical + 1;
return {
'&-edit-content': {
position: 'relative',
'div&': {
insetInlineStart: -token.paddingSM,
marginTop: -inputShift,
marginBottom: `calc(1em - ${inputShift}px)`,
},
[`${componentCls}-edit-content-confirm`]: {
position: 'absolute',
insetInlineEnd: token.marginXS + 2,
insetBlockEnd: token.marginXS,
color: token.colorTextDescription,
// default style
fontWeight: 'normal',
fontSize: token.fontSize,
fontStyle: 'normal',
pointerEvents: 'none',
},
textarea: {
margin: '0!important',
// Fix Editable Textarea flash in Firefox
MozTransition: 'none',
height: '1em',
},
},
};
};
export const getCopiableStyles: GenerateStyle<TypographyToken, CSSObject> = token => ({
'&-copy-success': {
[`
&,
&:hover,
&:focus`]: {
color: token.colorSuccess,
},
},
});
export const getEllipsisStyles = (): CSSObject => ({
[`
a&-ellipsis,
span&-ellipsis
`]: {
display: 'inline-block',
maxWidth: '100%',
},
'&-single-line': {
whiteSpace: 'nowrap',
},
'&-ellipsis-single-line': {
overflow: 'hidden',
textOverflow: 'ellipsis',
// https://blog.csdn.net/iefreer/article/details/50421025
'a&, span&': {
verticalAlign: 'bottom',
},
},
'&-ellipsis-multiple-line': {
display: '-webkit-box',
overflow: 'hidden',
WebkitLineClamp: 3,
WebkitBoxOrient: 'vertical',
},
});

View File

@ -1,54 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@typography-prefix-cls: ~'@{ant-prefix}-typography';
.@{typography-prefix-cls} {
&-rtl {
direction: rtl;
}
// Operation
&-expand,
&-edit,
&-copy {
.@{typography-prefix-cls}-rtl & {
margin-right: 4px;
margin-left: 0;
}
}
&-expand {
.@{typography-prefix-cls}-rtl & {
float: left;
}
}
// Text input area
&-edit-content {
div& {
&.@{typography-prefix-cls}-rtl {
right: -@input-padding-horizontal - 1px;
left: auto;
}
}
&-confirm {
.@{typography-prefix-cls}-rtl & {
right: auto;
left: 10px;
}
}
}
// list
ul,
ol {
li {
.@{typography-prefix-cls}-rtl& {
margin: 0 20px 0 0;
padding: 0 4px 0 0;
}
}
}
}