UNPKG

antd

Version:

An enterprise-class UI design language and React components implementation

409 lines • 13.4 kB
import { unit } from '@ant-design/cssinjs'; import { FastColor } from '@ant-design/fast-color'; import { genStyleHooks, mergeToken } from '../../theme/internal'; import { genFocusOutline, genFocusStyle } from '../../style'; import { inkFlow1, inkFlow2, inkFlow3, progressActive } from './progressAnimation'; export const genBoxStyle = position => ({ position: position || 'absolute', inset: 0 }); export const genImageCoverStyle = token => { const { componentCls, motionDurationSlow, colorTextLightSolid } = token; return { [componentCls]: { [`${componentCls}-cover`]: { position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: colorTextLightSolid, background: new FastColor('#000').setA(0.3).toRgbString(), cursor: 'pointer', opacity: 0, transition: `opacity ${motionDurationSlow}` }, '&:hover, &:focus-visible': { [`${componentCls}-cover`]: { opacity: 1 } }, [`${componentCls}-cover-top`]: { inset: '0 0 auto 0', justifyContent: 'center' }, [`${componentCls}-cover-bottom`]: { inset: 'auto 0 0 0', justifyContent: 'center' } } }; }; export const genImageProgressStyle = token => { const { componentCls, motionDurationMid, motionEaseInOut, progressAnimationDuration } = token; // Common ink layer base styles const inkBaseStyle = { position: 'absolute', width: '150%', height: '150%', left: '-25%', top: '-25%', animationTimingFunction: motionEaseInOut, animationIterationCount: 'infinite', pointerEvents: 'none', willChange: 'transform, opacity' }; return { // Progress root (wrapper) [`${componentCls}-progress-wrapper`]: { position: 'relative', display: 'inline-block', overflow: 'hidden', borderRadius: 'inherit', backgroundColor: token.colorBgBase, backdropFilter: 'blur(8px)', // Ink group 1: Ink 1 (main) + Ink 2 (::before) + Ink 3 (::after) [`${componentCls}-progress-ink-1`]: { ...inkBaseStyle, // Ink 1 - Top left blue cloud background: `radial-gradient(ellipse 65% 55% at 25% 30%, rgba(100, 180, 255, 0.98) 0%, transparent 55%)`, animationName: inkFlow1, animationDuration: progressAnimationDuration, filter: 'blur(40px)', // Ink 2 - Center right lavender '&::before': { content: '""', ...inkBaseStyle, background: `radial-gradient(ellipse 60% 65% at 75% 45%, rgba(180, 140, 255, 0.95) 0%, transparent 50%)`, animationName: inkFlow2, animationDuration: `calc(${progressAnimationDuration} + 2s)`, animationDelay: '-1s', filter: 'blur(45px)' }, // Ink 3 - Bottom center cyan '&::after': { content: '""', ...inkBaseStyle, background: `radial-gradient(ellipse 55% 50% at 50% 70%, rgba(100, 220, 220, 0.9) 0%, transparent 45%)`, animationName: inkFlow3, animationDuration: `calc(${progressAnimationDuration} + 0.5s)`, animationDelay: '-2s', filter: 'blur(38px)' } }, // Ink group 2: Ink 4 (main) + Ink 5 (::before) [`${componentCls}-progress-ink-2`]: { ...inkBaseStyle, // Ink 4 - Scattered pink blossom background: `radial-gradient(ellipse 45% 40% at 60% 20%, rgba(255, 150, 200, 0.88) 0%, transparent 45%)`, animationName: inkFlow3, animationDuration: `calc(${progressAnimationDuration} + 1.5s)`, animationDelay: '-3s', filter: 'blur(42px)', // Ink 5 - Soft periwinkle accent '&::before': { content: '""', ...inkBaseStyle, background: `radial-gradient(ellipse 50% 55% at 20% 75%, rgba(160, 190, 255, 0.88) 0%, transparent 50%)`, animationName: inkFlow1, animationDuration: `calc(${progressAnimationDuration} + 2.5s)`, animationDelay: '-2.5s', filter: 'blur(35px)' } }, // Progress content [`${componentCls}-progress-content`]: { position: 'absolute', top: '50%', left: 0, transform: 'translateY(-50%)', display: 'flex', flexDirection: 'column', alignItems: 'center', width: '100%', paddingInline: token.paddingLG, textAlign: 'center', fontSize: token.fontSize, color: token.colorTextSecondary, zIndex: 1 }, // Progress rail (background container) [`${componentCls}-progress-rail`]: { width: '100%', height: 6, marginTop: token.marginSM, backgroundColor: 'rgba(255, 255, 255, 0.5)', borderRadius: token.borderRadiusXS, overflow: 'hidden', backdropFilter: 'blur(4px)', // Track (filled portion) using ::before '&::before': { content: '""', display: 'block', height: '100%', width: 'var(--progress-percent, 0%)', background: 'linear-gradient(90deg, rgba(120, 170, 255, 0.85) 0%, rgba(160, 150, 245, 0.85) 40%, rgba(130, 200, 220, 0.85) 60%, rgba(120, 170, 255, 0.85) 100%)', backgroundSize: '200% 100%', borderRadius: token.borderRadiusXS / 2, transition: `width ${motionDurationMid} ease`, animationName: progressActive, animationDuration: progressAnimationDuration, animationTimingFunction: 'linear', animationIterationCount: 'infinite' } }, // Progress indicator (percent text) [`${componentCls}-progress-indicator`]: { marginTop: token.marginXS } } }; }; export const genImagePreviewStyle = token => { const { motionEaseOut, previewCls, motionDurationSlow, componentCls, colorBgMask, marginXL, marginSM, margin, colorTextLightSolid, paddingSM, paddingLG, previewOperationHoverColor, previewOperationColorDisabled, previewOperationSize, zIndexPopup } = token; const operationBg = new FastColor(colorBgMask).setA(0.1); const operationBgHover = operationBg.clone().setA(0.2); const singleBtn = { position: 'absolute', color: colorTextLightSolid, backgroundColor: operationBg.toRgbString(), borderRadius: '50%', padding: paddingSM, outline: 0, border: 0, cursor: 'pointer', transition: `all ${motionDurationSlow}`, display: 'flex', fontSize: previewOperationSize, '&:hover': { backgroundColor: operationBgHover.toRgbString() }, '&:active': { backgroundColor: operationBg.toRgbString() }, '&:focus-visible': genFocusOutline(token) }; return { [`${componentCls}-preview`]: { textAlign: 'center', inset: 0, position: 'fixed', userSelect: 'none', zIndex: zIndexPopup, // ================= Mask ================= [`${previewCls}-mask`]: { inset: 0, position: 'absolute', background: colorBgMask, backdropFilter: 'blur(0px)', transition: `backdrop-filter ${motionDurationSlow}`, [`&${componentCls}-preview-mask-blur`]: { backdropFilter: 'blur(4px)' }, [`&${componentCls}-preview-mask-hidden`]: { display: 'none' } }, // ================= Body ================= [`${previewCls}-body`]: { ...genBoxStyle(), 'pointer-events': 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', '> *': { pointerEvents: 'auto' } }, // Body > Image [`${previewCls}-img`]: { maxWidth: '100%', maxHeight: '70%', verticalAlign: 'middle', transform: 'scale3d(1, 1, 1)', transition: `transform ${motionDurationSlow} ${motionEaseOut} 0s` }, [`&-movable ${previewCls}-img`]: { cursor: 'grab' }, [`&-moving ${previewCls}-img`]: { cursor: 'grabbing' }, // =============== CloseBtn =============== [`${previewCls}-close`]: { // Shared style ...singleBtn, top: marginSM, insetInlineEnd: marginSM }, // ================ Switch ================ [`${previewCls}-switch`]: { ...singleBtn, top: '50%', transform: `translateY(-50%)`, '&-disabled': { '&, &:hover, &:active': { color: previewOperationColorDisabled, background: 'transparent', cursor: 'not-allowed' } }, '&-prev': { insetInlineStart: marginSM }, '&-next': { insetInlineEnd: marginSM } }, // ================ Footer ================ [`${previewCls}-footer`]: { position: 'absolute', bottom: marginXL, left: { _skip_check_: true, value: '50%' }, display: 'flex', flexDirection: 'column', alignItems: 'center', color: token.previewOperationColor, transform: 'translateX(-50%)', gap: margin }, // =============== Actions ================ [`${previewCls}-actions`]: { display: 'flex', gap: paddingSM, padding: `0 ${unit(paddingLG)}`, backgroundColor: operationBg.toRgbString(), borderRadius: 100, fontSize: previewOperationSize, '&-action': { color: 'inherit', background: 'transparent', border: 0, font: 'inherit', padding: paddingSM, cursor: 'pointer', transition: `all ${motionDurationSlow}`, display: 'flex', [`&:not(${previewCls}-actions-action-disabled):hover`]: { color: previewOperationHoverColor }, '&:focus-visible': genFocusOutline(token), '&-disabled': { color: previewOperationColorDisabled, cursor: 'not-allowed' } } } } }; }; const genImageStyle = token => { const { componentCls } = token; return { // ============================== image ============================== [componentCls]: { position: 'relative', display: 'inline-block', ...genFocusStyle(token), [`${componentCls}-img`]: { width: '100%', height: 'auto', verticalAlign: 'middle' }, [`${componentCls}-img-placeholder`]: { backgroundColor: token.colorBgContainerDisabled, backgroundImage: "url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=')", backgroundRepeat: 'no-repeat', backgroundPosition: 'center center', backgroundSize: '30%' }, [`${componentCls}-placeholder`]: { ...genBoxStyle() } } }; }; const genPreviewMotion = token => { const { previewCls, motionDurationSlow } = token; return { [previewCls]: { '&-fade': { transition: `opacity ${motionDurationSlow}`, '&-enter, &-appear': { opacity: 0, [`${previewCls}-body`]: { transform: 'scale(0)' }, '&-active': { opacity: 1, [`${previewCls}-body`]: { transform: 'scale(1)', transition: `transform ${motionDurationSlow}` } } }, '&-leave': { opacity: 1, '&-active': { opacity: 0, [`${previewCls}-body`]: { transform: 'scale(0)', transition: `transform ${motionDurationSlow}` } } } } } }; }; // ============================== Export ============================== export const prepareComponentToken = token => ({ zIndexPopup: token.zIndexPopupBase + 80, previewOperationColor: new FastColor(token.colorTextLightSolid).setA(0.65).toRgbString(), previewOperationHoverColor: new FastColor(token.colorTextLightSolid).setA(0.85).toRgbString(), previewOperationColorDisabled: new FastColor(token.colorTextLightSolid).setA(0.25).toRgbString(), previewOperationSize: token.fontSizeIcon * 1.5, // FIXME: fontSizeIconLG progressAnimationDuration: '3s' }); export default genStyleHooks('Image', token => { const previewCls = `${token.componentCls}-preview`; const imageToken = mergeToken(token, { previewCls, imagePreviewSwitchSize: token.controlHeightLG }); return [genImageStyle(imageToken), genImageCoverStyle(imageToken), genImageProgressStyle(imageToken), genImagePreviewStyle(imageToken), genPreviewMotion(imageToken)]; }, prepareComponentToken);