From 35cb77ade568b0c4297fe459d79e6dcd9f3345d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E9=9B=A8?= Date: Tue, 29 Mar 2022 20:55:44 +0800 Subject: [PATCH] feat: cssinjs for skeleton (#34698) * feat: cssinjs for skeleton * feat: update for review * feat: update for style * feat: update for style --- components/skeleton/Avatar.tsx | 8 +- components/skeleton/Button.tsx | 8 +- components/skeleton/Image.tsx | 8 +- components/skeleton/Input.tsx | 8 +- components/skeleton/Skeleton.tsx | 7 +- components/skeleton/style/index.less | 570 +++++++++++++-------------- components/skeleton/style/index.tsx | 384 +++++++++++++++++- 7 files changed, 695 insertions(+), 298 deletions(-) diff --git a/components/skeleton/Avatar.tsx b/components/skeleton/Avatar.tsx index c708829d91..cdbdd65ddc 100644 --- a/components/skeleton/Avatar.tsx +++ b/components/skeleton/Avatar.tsx @@ -3,6 +3,7 @@ import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; import { ConfigContext } from '../config-provider'; import Element, { SkeletonElementProps } from './Element'; +import useStyle from './style'; export interface AvatarProps extends Omit { shape?: 'circle' | 'square'; @@ -12,6 +13,7 @@ const SkeletonAvatar = (props: AvatarProps) => { const { prefixCls: customizePrefixCls, className, active } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls); const otherProps = omit(props, ['prefixCls', 'className']); const cls = classNames( @@ -21,11 +23,13 @@ const SkeletonAvatar = (props: AvatarProps) => { [`${prefixCls}-active`]: active, }, className, + hashId, ); - return ( + + return wrapSSR(
-
+ , ); }; diff --git a/components/skeleton/Button.tsx b/components/skeleton/Button.tsx index 5ca1872257..1841a33ca8 100644 --- a/components/skeleton/Button.tsx +++ b/components/skeleton/Button.tsx @@ -3,6 +3,7 @@ import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; import Element, { SkeletonElementProps } from './Element'; import { ConfigContext } from '../config-provider'; +import useStyle from './style'; export interface SkeletonButtonProps extends Omit { size?: 'large' | 'small' | 'default'; @@ -13,6 +14,7 @@ const SkeletonButton = (props: SkeletonButtonProps) => { const { prefixCls: customizePrefixCls, className, active, block = false } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls); const otherProps = omit(props, ['prefixCls']); const cls = classNames( @@ -23,11 +25,13 @@ const SkeletonButton = (props: SkeletonButtonProps) => { [`${prefixCls}-block`]: block, }, className, + hashId, ); - return ( + + return wrapSSR(
-
+ , ); }; diff --git a/components/skeleton/Image.tsx b/components/skeleton/Image.tsx index 3f31a7179b..288218e86f 100644 --- a/components/skeleton/Image.tsx +++ b/components/skeleton/Image.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import classNames from 'classnames'; import { SkeletonElementProps } from './Element'; import { ConfigContext } from '../config-provider'; +import useStyle from './style'; export interface SkeletonImageProps extends Omit {} @@ -13,9 +14,10 @@ const SkeletonImage = (props: SkeletonImageProps) => { const { prefixCls: customizePrefixCls, className, style } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); - const cls = classNames(prefixCls, `${prefixCls}-element`, className); + const [wrapSSR, hashId] = useStyle(prefixCls); + const cls = classNames(prefixCls, `${prefixCls}-element`, className, hashId); - return ( + return wrapSSR(
{
-
+ , ); }; diff --git a/components/skeleton/Input.tsx b/components/skeleton/Input.tsx index 61532c4756..c47cbf3f71 100644 --- a/components/skeleton/Input.tsx +++ b/components/skeleton/Input.tsx @@ -3,6 +3,7 @@ import omit from 'rc-util/lib/omit'; import classNames from 'classnames'; import Element, { SkeletonElementProps } from './Element'; import { ConfigContext } from '../config-provider'; +import useStyle from './style'; export interface SkeletonInputProps extends Omit { size?: 'large' | 'small' | 'default'; @@ -13,6 +14,7 @@ const SkeletonInput = (props: SkeletonInputProps) => { const { prefixCls: customizePrefixCls, className, active, block } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls); const otherProps = omit(props, ['prefixCls']); const cls = classNames( @@ -23,11 +25,13 @@ const SkeletonInput = (props: SkeletonInputProps) => { [`${prefixCls}-block`]: block, }, className, + hashId, ); - return ( + + return wrapSSR(
-
+ , ); }; diff --git a/components/skeleton/Skeleton.tsx b/components/skeleton/Skeleton.tsx index 6fcc736e4b..005a9ed82c 100644 --- a/components/skeleton/Skeleton.tsx +++ b/components/skeleton/Skeleton.tsx @@ -8,6 +8,7 @@ import SkeletonAvatar, { AvatarProps } from './Avatar'; import SkeletonButton from './Button'; import SkeletonInput from './Input'; import SkeletonImage from './Image'; +import useStyle from './style'; /* This only for skeleton internal. */ interface SkeletonAvatarProps extends Omit {} @@ -87,6 +88,7 @@ const Skeleton = (props: SkeletonProps) => { const { getPrefixCls, direction } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('skeleton', customizePrefixCls); + const [wrapSSR, hashId] = useStyle(prefixCls); if (loading || !('loading' in props)) { const hasAvatar = !!avatar; @@ -152,13 +154,14 @@ const Skeleton = (props: SkeletonProps) => { [`${prefixCls}-round`]: round, }, className, + hashId, ); - return ( + return wrapSSR(
{avatarNode} {contentNode} -
+ , ); } return children as React.ReactElement; diff --git a/components/skeleton/style/index.less b/components/skeleton/style/index.less index c4ca85b58f..c12a34187b 100644 --- a/components/skeleton/style/index.less +++ b/components/skeleton/style/index.less @@ -1,285 +1,285 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; - -@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton'; -@skeleton-avatar-prefix-cls: ~'@{skeleton-prefix-cls}-avatar'; -@skeleton-title-prefix-cls: ~'@{skeleton-prefix-cls}-title'; -@skeleton-paragraph-prefix-cls: ~'@{skeleton-prefix-cls}-paragraph'; -@skeleton-button-prefix-cls: ~'@{skeleton-prefix-cls}-button'; -@skeleton-input-prefix-cls: ~'@{skeleton-prefix-cls}-input'; -@skeleton-image-prefix-cls: ~'@{skeleton-prefix-cls}-image'; -@skeleton-block-radius: 4px; - -.@{skeleton-prefix-cls} { - display: table; - width: 100%; - - &-header { - display: table-cell; - padding-right: @padding-md; - vertical-align: top; - - // Avatar - .@{skeleton-avatar-prefix-cls} { - .skeleton-element-avatar(); - } - } - - &-content { - display: table-cell; - width: 100%; - vertical-align: top; - - // Title - .@{skeleton-title-prefix-cls} { - width: 100%; - height: @skeleton-title-height; - margin-top: @margin-md; - background: @skeleton-color; - border-radius: @skeleton-block-radius; - - + .@{skeleton-paragraph-prefix-cls} { - margin-top: @skeleton-title-paragraph-margin-top; - } - } - - // paragraph - .@{skeleton-paragraph-prefix-cls} { - padding: 0; - - > li { - width: 100%; - height: @skeleton-paragraph-li-height; - list-style: none; - background: @skeleton-color; - border-radius: @skeleton-block-radius; - - &:last-child:not(:first-child):not(:nth-child(2)) { - width: 61%; - } - - + li { - margin-top: @skeleton-paragraph-li-margin-top; - } - } - } - } - - &-with-avatar &-content { - // Title - .@{skeleton-title-prefix-cls} { - margin-top: @margin-sm; - - + .@{skeleton-paragraph-prefix-cls} { - margin-top: @skeleton-paragraph-margin-top; - } - } - } - - &-round &-content { - .@{skeleton-title-prefix-cls}, - .@{skeleton-paragraph-prefix-cls} > li { - border-radius: 100px; - } - } - - // With active animation - &.@{skeleton-prefix-cls}-active { - & .@{skeleton-prefix-cls}-content { - .@{skeleton-title-prefix-cls}, - .@{skeleton-paragraph-prefix-cls} > li { - .skeleton-color(); - } - } - - .@{skeleton-avatar-prefix-cls} { - .skeleton-color(); - } - - .@{skeleton-button-prefix-cls} { - .skeleton-color(); - } - - .@{skeleton-input-prefix-cls} { - .skeleton-color(); - } - - .@{skeleton-image-prefix-cls} { - .skeleton-color(); - } - } - - // Skeleton Block Button, Input - &.@{skeleton-prefix-cls}-block { - width: 100%; - - .@{skeleton-button-prefix-cls} { - width: 100%; - } - - .@{skeleton-input-prefix-cls} { - width: 100%; - } - } - - // Skeleton element - &-element { - display: inline-block; - width: auto; - - .@{skeleton-button-prefix-cls} { - .skeleton-element-button(); - } - - .@{skeleton-avatar-prefix-cls} { - .skeleton-element-avatar(); - } - - .@{skeleton-input-prefix-cls} { - .skeleton-element-input(); - } - - .@{skeleton-image-prefix-cls} { - .skeleton-element-image(); - } - } -} -// Button -.skeleton-element-button() { - display: inline-block; - vertical-align: top; - background: @skeleton-color; - border-radius: @border-radius-base; - - .skeleton-element-button-size(@btn-height-base); - - &-lg { - .skeleton-element-button-size(@btn-height-lg); - } - - &-sm { - .skeleton-element-button-size(@btn-height-sm); - } -} -// Avatar -.skeleton-element-avatar() { - display: inline-block; - vertical-align: top; - background: @skeleton-color; - - .skeleton-element-avatar-size(@avatar-size-base); - - &-lg { - .skeleton-element-avatar-size(@avatar-size-lg); - } - - &-sm { - .skeleton-element-avatar-size(@avatar-size-sm); - } -} - -// Input -.skeleton-element-input() { - display: inline-block; - vertical-align: top; - background: @skeleton-color; - - .skeleton-element-input-size(@input-height-base); - - &-lg { - .skeleton-element-input-size(@input-height-lg); - } - - &-sm { - .skeleton-element-input-size(@input-height-sm); - } -} - -// Image -.skeleton-element-image() { - display: flex; - align-items: center; - justify-content: center; - vertical-align: top; - background: @skeleton-color; - - .skeleton-element-image-size(@image-size-base*2); - - &-path { - fill: #bfbfbf; - } - - &-svg { - .skeleton-element-image-size(@image-size-base); - max-width: @image-size-base * 4; - max-height: @image-size-base * 4; - } -} - -.skeleton-element-avatar-size(@size) { - width: @size; - .skeleton-element-common-size(@size); - - &.@{skeleton-avatar-prefix-cls}-circle { - border-radius: 50%; - } -} - -.skeleton-element-button-size(@size) { - width: @size * 2; - min-width: @size * 2; - .skeleton-element-common-size(@size); - - &.@{skeleton-button-prefix-cls}-circle { - width: @size; - min-width: @size; - border-radius: 50%; - } - - &.@{skeleton-button-prefix-cls}-round { - border-radius: @size; - } -} - -.skeleton-element-input-size(@size) { - width: @size * 5; - min-width: @size * 5; - .skeleton-element-common-size(@size); -} - -.skeleton-element-image-size(@size) { - width: @size; - .skeleton-element-common-size(@size); - - &.@{skeleton-image-prefix-cls}-circle { - border-radius: 50%; - } -} - -.skeleton-element-common-size(@size) { - height: @size; - line-height: @size; -} - -.skeleton-color() { - background: linear-gradient( - 90deg, - @skeleton-color 25%, - @skeleton-to-color 37%, - @skeleton-color 63% - ); - background-size: 400% 100%; - animation: ~'@{skeleton-prefix-cls}-loading' 1.4s ease infinite; -} - -@keyframes ~"@{skeleton-prefix-cls}-loading" { - 0% { - background-position: 100% 50%; - } - - 100% { - background-position: 0 50%; - } -} - -@import './rtl'; +//@import '../../style/themes/index'; +//@import '../../style/mixins/index'; +// +//@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton'; +//@skeleton-avatar-prefix-cls: ~'@{skeleton-prefix-cls}-avatar'; +//@skeleton-title-prefix-cls: ~'@{skeleton-prefix-cls}-title'; +//@skeleton-paragraph-prefix-cls: ~'@{skeleton-prefix-cls}-paragraph'; +//@skeleton-button-prefix-cls: ~'@{skeleton-prefix-cls}-button'; +//@skeleton-input-prefix-cls: ~'@{skeleton-prefix-cls}-input'; +//@skeleton-image-prefix-cls: ~'@{skeleton-prefix-cls}-image'; +//@skeleton-block-radius: 4px; +// +//.@{skeleton-prefix-cls} { +// display: table; +// width: 100%; +// +// &-header { +// display: table-cell; +// padding-right: @padding-md; +// vertical-align: top; +// +// // Avatar +// .@{skeleton-avatar-prefix-cls} { +// .skeleton-element-avatar(); +// } +// } +// +// &-content { +// display: table-cell; +// width: 100%; +// vertical-align: top; +// +// // Title +// .@{skeleton-title-prefix-cls} { +// width: 100%; +// height: @skeleton-title-height; +// margin-top: @margin-md; +// background: @skeleton-color; +// border-radius: @skeleton-block-radius; +// +// + .@{skeleton-paragraph-prefix-cls} { +// margin-top: @skeleton-title-paragraph-margin-top; +// } +// } +// +// // paragraph +// .@{skeleton-paragraph-prefix-cls} { +// padding: 0; +// +// > li { +// width: 100%; +// height: @skeleton-paragraph-li-height; +// list-style: none; +// background: @skeleton-color; +// border-radius: @skeleton-block-radius; +// +// &:last-child:not(:first-child):not(:nth-child(2)) { +// width: 61%; +// } +// +// + li { +// margin-top: @skeleton-paragraph-li-margin-top; +// } +// } +// } +// } +// +// &-with-avatar &-content { +// // Title +// .@{skeleton-title-prefix-cls} { +// margin-top: @margin-sm; +// +// + .@{skeleton-paragraph-prefix-cls} { +// margin-top: @skeleton-paragraph-margin-top; +// } +// } +// } +// +// &-round &-content { +// .@{skeleton-title-prefix-cls}, +// .@{skeleton-paragraph-prefix-cls} > li { +// border-radius: 100px; +// } +// } +// +// // With active animation +// &.@{skeleton-prefix-cls}-active { +// & .@{skeleton-prefix-cls}-content { +// .@{skeleton-title-prefix-cls}, +// .@{skeleton-paragraph-prefix-cls} > li { +// .skeleton-color(); +// } +// } +// +// .@{skeleton-avatar-prefix-cls} { +// .skeleton-color(); +// } +// +// .@{skeleton-button-prefix-cls} { +// .skeleton-color(); +// } +// +// .@{skeleton-input-prefix-cls} { +// .skeleton-color(); +// } +// +// .@{skeleton-image-prefix-cls} { +// .skeleton-color(); +// } +// } +// +// // Skeleton Block Button, Input +// &.@{skeleton-prefix-cls}-block { +// width: 100%; +// +// .@{skeleton-button-prefix-cls} { +// width: 100%; +// } +// +// .@{skeleton-input-prefix-cls} { +// width: 100%; +// } +// } +// +// // Skeleton element +// &-element { +// display: inline-block; +// width: auto; +// +// .@{skeleton-button-prefix-cls} { +// .skeleton-element-button(); +// } +// +// .@{skeleton-avatar-prefix-cls} { +// .skeleton-element-avatar(); +// } +// +// .@{skeleton-input-prefix-cls} { +// .skeleton-element-input(); +// } +// +// .@{skeleton-image-prefix-cls} { +// .skeleton-element-image(); +// } +// } +//} +//// Button +//.skeleton-element-button() { +// display: inline-block; +// vertical-align: top; +// background: @skeleton-color; +// border-radius: @border-radius-base; +// +// .skeleton-element-button-size(@btn-height-base); +// +// &-lg { +// .skeleton-element-button-size(@btn-height-lg); +// } +// +// &-sm { +// .skeleton-element-button-size(@btn-height-sm); +// } +//} +//// Avatar +//.skeleton-element-avatar() { +// display: inline-block; +// vertical-align: top; +// background: @skeleton-color; +// +// .skeleton-element-avatar-size(@avatar-size-base); +// +// &-lg { +// .skeleton-element-avatar-size(@avatar-size-lg); +// } +// +// &-sm { +// .skeleton-element-avatar-size(@avatar-size-sm); +// } +//} +// +//// Input +//.skeleton-element-input() { +// display: inline-block; +// vertical-align: top; +// background: @skeleton-color; +// +// .skeleton-element-input-size(@input-height-base); +// +// &-lg { +// .skeleton-element-input-size(@input-height-lg); +// } +// +// &-sm { +// .skeleton-element-input-size(@input-height-sm); +// } +//} +// +//// Image +//.skeleton-element-image() { +// display: flex; +// align-items: center; +// justify-content: center; +// vertical-align: top; +// background: @skeleton-color; +// +// .skeleton-element-image-size(@image-size-base*2); +// +// &-path { +// fill: #bfbfbf; +// } +// +// &-svg { +// .skeleton-element-image-size(@image-size-base); +// max-width: @image-size-base * 4; +// max-height: @image-size-base * 4; +// } +//} +// +//.skeleton-element-avatar-size(@size) { +// width: @size; +// .skeleton-element-common-size(@size); +// +// &.@{skeleton-avatar-prefix-cls}-circle { +// border-radius: 50%; +// } +//} +// +//.skeleton-element-button-size(@size) { +// width: @size * 2; +// min-width: @size * 2; +// .skeleton-element-common-size(@size); +// +// &.@{skeleton-button-prefix-cls}-circle { +// width: @size; +// min-width: @size; +// border-radius: 50%; +// } +// +// &.@{skeleton-button-prefix-cls}-round { +// border-radius: @size; +// } +//} +// +//.skeleton-element-input-size(@size) { +// width: @size * 5; +// min-width: @size * 5; +// .skeleton-element-common-size(@size); +//} +// +//.skeleton-element-image-size(@size) { +// width: @size; +// .skeleton-element-common-size(@size); +// +// &.@{skeleton-image-prefix-cls}-circle { +// border-radius: 50%; +// } +//} +// +//.skeleton-element-common-size(@size) { +// height: @size; +// line-height: @size; +//} +// +//.skeleton-color() { +// background: linear-gradient( +// 90deg, +// @skeleton-color 25%, +// @skeleton-to-color 37%, +// @skeleton-color 63% +// ); +// background-size: 400% 100%; +// animation: ~'@{skeleton-prefix-cls}-loading' 1.4s ease infinite; +//} +// +//@keyframes ~"@{skeleton-prefix-cls}-loading" { +// 0% { +// background-position: 100% 50%; +// } +// +// 100% { +// background-position: 0 50%; +// } +//} +// +//@import './rtl'; diff --git a/components/skeleton/style/index.tsx b/components/skeleton/style/index.tsx index 3a3ab0de59..d7d84c7978 100644 --- a/components/skeleton/style/index.tsx +++ b/components/skeleton/style/index.tsx @@ -1,2 +1,382 @@ -import '../../style/index.less'; -import './index.less'; +// deps-lint-skip-all +import { CSSObject, Keyframes } from '@ant-design/cssinjs'; + +import { + DerivativeToken, + useStyleRegister, + useToken, + UseComponentStyleResult, + GenerateStyle, +} from '../../_util/theme'; + +const skeletonClsLoading = new Keyframes(`ant-skeleton-loading`, { + '0%': { + backgroundPosition: '100% 50%', + }, + '100%': { + backgroundPosition: '0 50%', + }, +}); + +interface SkeletonToken extends DerivativeToken { + skeletonCls: string; + prefixCls: string; + skeletonAvatarCls: string; + skeletonTitleCls: string; + skeletonParagraphCls: string; + skeletonButtonCls: string; + skeletonInputCls: string; + skeletonImageCls: string; + skeletonColor: string; + skeletonToColor: string; + imageSizeBase: number; + imageFontSizeBase: number; + skeletonTitleHeight: number; + skeletonBlockRadius: number; + skeletonParagraphLiHeight: number; + skeletonParagraphMarginTop: number; + borderRadius: number; +} + +const genSkeletonElementCommonSize = (size: number): CSSObject => ({ + height: size, + lineHeight: `${size}px`, +}); + +const genSkeletonElementAvatarSize = (size: number): CSSObject => ({ + width: size, + ...genSkeletonElementCommonSize(size), +}); + +const genSkeletonColor = (token: SkeletonToken, hashId: string): CSSObject => { + const { skeletonColor, skeletonToColor } = token; + return { + background: `linear-gradient(90deg, ${skeletonColor} 25%, ${skeletonToColor} 37%, ${skeletonColor} 63%)`, + backgroundSize: '400% 100%', + animation: `${skeletonClsLoading.getName(hashId)} 1.4s ease infinite`, + skeletonClsLoading, + }; +}; + +const genSkeletonElementInputSize = (size: number): CSSObject => ({ + width: size * 5, + minWidth: size * 5, + ...genSkeletonElementCommonSize(size), +}); + +const genSkeletonElementAvatar = (token: SkeletonToken): CSSObject => { + const { skeletonAvatarCls, skeletonColor, controlHeight, controlHeightLG, controlHeightSM } = + token; + return { + [`${skeletonAvatarCls}`]: { + display: 'inline-block', + verticalAlign: 'top', + background: skeletonColor, + ...genSkeletonElementAvatarSize(controlHeight), + }, + [`${skeletonAvatarCls}${skeletonAvatarCls}-circle`]: { + borderRadius: '50%', + }, + [`${skeletonAvatarCls}${skeletonAvatarCls}-lg`]: { + ...genSkeletonElementAvatarSize(controlHeightLG), + }, + [`${skeletonAvatarCls}${skeletonAvatarCls}-sm`]: { + ...genSkeletonElementAvatarSize(controlHeightSM), + }, + }; +}; + +const genSkeletonElementInput = (token: SkeletonToken): CSSObject => { + const { controlHeight, skeletonInputCls, controlHeightLG, controlHeightSM, skeletonColor } = + token; + return { + [`${skeletonInputCls}`]: { + display: 'inline-block', + verticalAlign: 'top', + background: skeletonColor, + ...genSkeletonElementInputSize(controlHeight), + }, + + [`${skeletonInputCls}-lg`]: { + ...genSkeletonElementInputSize(controlHeightLG), + }, + + [`${skeletonInputCls}-sm`]: { + ...genSkeletonElementInputSize(controlHeightSM), + }, + }; +}; + +const genSkeletonElementImageSize = (size: number): CSSObject => ({ + width: size, + ...genSkeletonElementCommonSize(size), +}); + +const genSkeletonElementImage = (token: SkeletonToken): CSSObject => { + const { skeletonImageCls, imageSizeBase, skeletonColor } = token; + return { + [`${skeletonImageCls}`]: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + verticalAlign: 'top', + background: skeletonColor, + ...genSkeletonElementImageSize(imageSizeBase * 2), + [`${skeletonImageCls}-path`]: { + fill: '#bfbfbf', + }, + [`${skeletonImageCls}-svg`]: { + ...genSkeletonElementImageSize(imageSizeBase), + maxWidth: imageSizeBase * 4, + maxHeight: imageSizeBase * 4, + }, + [`${skeletonImageCls}-svg${skeletonImageCls}-svg-circle`]: { + borderRadius: '50%', + }, + }, + [`${skeletonImageCls}${skeletonImageCls}-circle`]: { + borderRadius: '50%', + }, + }; +}; +const genSkeletonElementButtonShape = ( + token: SkeletonToken, + size: number, + buttonCls: string, +): CSSObject => { + const { skeletonButtonCls } = token; + return { + [`${buttonCls}${skeletonButtonCls}-circle`]: { + width: size, + minWidth: size, + borderRadius: '50%', + }, + [`${buttonCls}${skeletonButtonCls}-round`]: { + borderRadius: size, + }, + }; +}; + +const genSkeletonElementButtonSize = (size: number): CSSObject => ({ + width: size * 2, + minWidth: size * 2, + ...genSkeletonElementCommonSize(size), +}); + +const genSkeletonElementButton = (token: SkeletonToken): CSSObject => { + const { + radiusBase, + skeletonButtonCls, + controlHeight, + controlHeightLG, + controlHeightSM, + skeletonColor, + } = token; + return { + [`${skeletonButtonCls}`]: { + display: 'inline-block', + verticalAlign: 'top', + background: skeletonColor, + borderRadius: radiusBase, + width: controlHeight * 2, + minWidth: controlHeight * 2, + ...genSkeletonElementButtonSize(controlHeight), + }, + ...genSkeletonElementButtonShape(token, controlHeight, skeletonButtonCls), + + [`${skeletonButtonCls}-lg`]: { + ...genSkeletonElementButtonSize(controlHeightLG), + }, + ...genSkeletonElementButtonShape(token, controlHeightLG, `${skeletonButtonCls}-lg`), + + [`${skeletonButtonCls}-sm`]: { + ...genSkeletonElementButtonSize(controlHeightSM), + }, + ...genSkeletonElementButtonShape(token, controlHeightSM, `${skeletonButtonCls}-sm`), + }; +}; + +// =============================== Base =============================== +const genBaseStyle: GenerateStyle = (token: SkeletonToken, hashId: string) => { + const { + skeletonCls, + skeletonAvatarCls, + skeletonTitleCls, + skeletonParagraphCls, + skeletonButtonCls, + skeletonInputCls, + skeletonImageCls, + controlHeight, + controlHeightLG, + controlHeightSM, + skeletonColor, + padding, + margin, + marginSM, + borderRadius, + skeletonTitleHeight, + skeletonBlockRadius, + skeletonParagraphLiHeight, + controlHeightXS, + skeletonParagraphMarginTop, + } = token; + + return { + [`${skeletonCls}`]: { + display: 'table', + width: '100%', + + [`${skeletonCls}-header`]: { + display: 'table-cell', + paddingInlineEnd: padding, + verticalAlign: 'top', + + // Avatar + [`${skeletonAvatarCls}`]: { + display: 'inline-block', + verticalAlign: 'top', + background: skeletonColor, + ...genSkeletonElementAvatarSize(controlHeight), + }, + [`${skeletonAvatarCls}-circle`]: { + borderRadius: '50%', + }, + [`${skeletonAvatarCls}-lg`]: { + ...genSkeletonElementAvatarSize(controlHeightLG), + }, + [`${skeletonAvatarCls}-sm`]: { + ...genSkeletonElementAvatarSize(controlHeightSM), + }, + }, + [`${skeletonCls}-content`]: { + display: 'table-cell', + width: '100%', + verticalAlign: 'top', + + // Title + [`${skeletonTitleCls}`]: { + width: '100%', + height: skeletonTitleHeight, + marginBlockStart: margin, + background: skeletonColor, + borderRadius: skeletonBlockRadius, + [`+ ${skeletonParagraphCls}`]: { + marginBlockStart: controlHeightSM, + }, + }, + + // paragraph + [`${skeletonParagraphCls}`]: { + padding: 0, + '> li': { + width: '100%', + height: skeletonParagraphLiHeight, + listStyle: 'none', + background: skeletonColor, + borderRadius: skeletonBlockRadius, + '+ li': { + marginBlockStart: controlHeightXS, + }, + }, + }, + + [`${skeletonParagraphCls}> li:last-child:not(:first-child):not(:nth-child(2))`]: { + width: '61%', + }, + }, + + [`${skeletonCls}-round ${skeletonCls}-content`]: { + [`${skeletonTitleCls}, ${skeletonTitleCls} > li`]: { + borderRadius, + }, + }, + }, + [`${skeletonCls}-with-avatar ${skeletonCls}-content`]: { + // Title + [`${skeletonTitleCls}`]: { + marginBlockStart: marginSM, + + [`+ ${skeletonParagraphCls}`]: { + marginBlockStart: skeletonParagraphMarginTop, + }, + }, + }, + // Skeleton element + [`${skeletonCls}${skeletonCls}-element`]: { + display: 'inline-block', + width: 'auto', + + ...genSkeletonElementButton(token), + ...genSkeletonElementAvatar(token), + ...genSkeletonElementInput(token), + ...genSkeletonElementImage(token), + }, + // Skeleton Block Button, Input + [`${skeletonCls}${skeletonCls}-block`]: { + width: '100%', + + [`${skeletonButtonCls}`]: { + width: '100%', + }, + + [`${skeletonInputCls}`]: { + width: '100%', + }, + }, + // With active animation + [`${skeletonCls}${skeletonCls}-active`]: { + [`${skeletonCls}-content`]: { + [`${skeletonTitleCls}, ${skeletonParagraphCls} > li`]: { + ...genSkeletonColor(token, hashId), + }, + }, + [`${skeletonAvatarCls}`]: { + ...genSkeletonColor(token, hashId), + }, + + [`${skeletonButtonCls}`]: { + ...genSkeletonColor(token, hashId), + }, + + [`${skeletonInputCls}`]: { + ...genSkeletonColor(token, hashId), + }, + [`${skeletonImageCls}`]: { + ...genSkeletonColor(token, hashId), + }, + }, + }; +}; + +// ============================== Export ============================== +export default function useStyle(prefixCls: string): UseComponentStyleResult { + const [theme, token, hashId] = useToken(); + + const skeletonToken: SkeletonToken = { + ...token, + prefixCls, + skeletonCls: `.${prefixCls}`, + skeletonAvatarCls: `.${prefixCls}-avatar`, + skeletonTitleCls: `.${prefixCls}-title`, + skeletonParagraphCls: `.${prefixCls}-paragraph`, + skeletonButtonCls: `.${prefixCls}-button`, + skeletonInputCls: `.${prefixCls}-input`, + skeletonImageCls: `.${prefixCls}-image`, + skeletonColor: 'rgba(190,190,190,0.2)', // FIXME: hard code in v4 + skeletonToColor: 'rgba(129,129,129,.24)', // FIXME: hard code in v4 + imageSizeBase: 48, // FIXME: hard code in v4 + imageFontSizeBase: 24, // FIXME: hard code in v4 + skeletonTitleHeight: 16, // FIXME: hard code in v4 + skeletonBlockRadius: 4, // FIXME: hard code in v4 + skeletonParagraphLiHeight: 16, // FIXME: hard code in v4 + skeletonParagraphMarginTop: 28, // FIXME: hard code in v4 + borderRadius: 100, // FIXME: hard code in v4 + }; + + return [ + useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => [ + genBaseStyle(skeletonToken, hashId), + ]), + hashId, + ]; +}