You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

381 lines
12 KiB

import type React from 'react';
import { initFadeMotion, initZoomMotion } from '../../style/motion';
import type { AliasToken, FullToken, GenerateStyle } from '../../theme';
import { genComponentStyleHook, mergeToken } from '../../theme';
import type { TokenWithCommonCls } from '../../theme/util/genComponentStyleHook';
import { clearFix, resetComponent } from '../../style';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
// Component token here
}
export interface ModalToken extends FullToken<'Modal'> {
// Custom token here
modalBodyPadding: number;
modalHeaderBg: string;
modalHeaderPadding: string;
modalHeaderBorderWidth: number;
modalHeaderBorderStyle: string;
modalHeaderTitleLineHeight: number;
modalHeaderTitleFontSize: number;
modalHeaderBorderColorSplit: string;
modalHeaderCloseSize: number;
modalContentBg: string;
modalHeadingColor: string;
modalCloseColor: string;
modalFooterBg: string;
modalFooterBorderColorSplit: string;
modalFooterBorderStyle: string;
modalFooterPaddingVertical: number;
modalFooterPaddingHorizontal: number;
modalFooterBorderWidth: number;
modalConfirmTitleFontSize: number;
modalIconHoverColor: string;
modalConfirmIconSize: number;
}
function box(position: React.CSSProperties['position']): React.CSSProperties {
return {
position,
top: 0,
insetInlineEnd: 0,
bottom: 0,
insetInlineStart: 0,
};
}
export const genModalMaskStyle: GenerateStyle<TokenWithCommonCls<AliasToken>> = token => {
const { componentCls } = token;
return [
{
[`${componentCls}-root`]: {
[`${componentCls}${token.antCls}-zoom-enter, ${componentCls}${token.antCls}-zoom-appear`]: {
// reset scale avoid mousePosition bug
transform: 'none',
opacity: 0,
animationDuration: token.motionDurationSlow,
// https://github.com/ant-design/ant-design/issues/11777
userSelect: 'none',
},
[`${componentCls}-mask`]: {
...box('fixed'),
zIndex: token.zIndexPopupBase,
height: '100%',
backgroundColor: token.colorBgMask,
[`${componentCls}-hidden`]: {
display: 'none',
},
},
[`${componentCls}-wrap`]: {
...box('fixed'),
overflow: 'auto',
outline: 0,
WebkitOverflowScrolling: 'touch',
},
},
},
{ [`${componentCls}-root`]: initFadeMotion(token) },
];
};
const genModalStyle: GenerateStyle<ModalToken> = token => {
const { componentCls } = token;
return [
// ======================== Root =========================
{
[`${componentCls}-root`]: {
[`${componentCls}-wrap`]: {
zIndex: token.zIndexPopupBase,
position: 'fixed',
inset: 0,
overflow: 'auto',
outline: 0,
WebkitOverflowScrolling: 'touch',
},
[`${componentCls}-wrap-rtl`]: {
direction: 'rtl',
},
[`${componentCls}-centered`]: {
textAlign: 'center',
'&::before': {
display: 'inline-block',
width: 0,
height: '100%',
verticalAlign: 'middle',
content: '""',
},
[componentCls]: {
top: 0,
display: 'inline-block',
paddingBottom: 0,
textAlign: 'start',
verticalAlign: 'middle',
},
},
[`@media (max-width: ${token.screenSMMax})`]: {
[componentCls]: {
maxWidth: 'calc(100vw - 16px)',
margin: `${token.marginXS} auto`,
},
[`${componentCls}-centered`]: {
[componentCls]: {
flex: 1,
},
},
},
},
},
// ======================== Modal ========================
{
[componentCls]: {
...resetComponent(token),
pointerEvents: 'none',
position: 'relative',
top: 100,
width: 'auto',
maxWidth: `calc(100vw - ${token.margin * 2}px)`,
margin: '0 auto',
paddingBottom: token.paddingLG,
[`${componentCls}-title`]: {
margin: 0,
color: token.modalHeadingColor,
fontWeight: token.fontWeightStrong,
fontSize: token.modalHeaderTitleFontSize,
lineHeight: token.modalHeaderTitleLineHeight,
wordWrap: 'break-word',
},
[`${componentCls}-content`]: {
position: 'relative',
backgroundColor: token.modalContentBg,
backgroundClip: 'padding-box',
border: 0,
borderRadius: token.controlRadius,
boxShadow: token.boxShadow,
pointerEvents: 'auto',
},
[`${componentCls}-close`]: {
position: 'absolute',
top: 0,
insetInlineEnd: 0,
zIndex: token.zIndexPopupBase + 10,
padding: 0,
color: token.modalCloseColor,
fontWeight: token.fontWeightStrong,
lineHeight: 1,
textDecoration: 'none',
background: 'transparent',
border: 0,
outline: 0,
cursor: 'pointer',
transition: `color ${token.motionDurationSlow}`,
'&-x': {
display: 'block',
width: token.modalHeaderCloseSize,
height: token.modalHeaderCloseSize,
fontSize: token.fontSizeLG,
fontStyle: 'normal',
lineHeight: `${token.modalHeaderCloseSize}px`,
textAlign: 'center',
textTransform: 'none',
textRendering: 'auto',
},
'&:focus, &:hover': {
color: token.modalIconHoverColor,
textDecoration: 'none',
},
},
[`${componentCls}-header`]: {
padding: token.modalHeaderPadding,
color: token.colorText,
background: token.modalHeaderBg,
borderBottom: `${token.modalHeaderBorderWidth}px ${token.modalHeaderBorderStyle} ${token.modalHeaderBorderColorSplit}`,
borderRadius: `${token.controlRadius}px ${token.controlRadius}px 0 0`,
},
[`${componentCls}-body`]: {
padding: token.modalBodyPadding,
fontSize: token.fontSizeBase,
lineHeight: token.lineHeight,
wordWrap: 'break-word',
},
[`${componentCls}-footer`]: {
padding: `${token.modalFooterPaddingVertical}px ${token.modalFooterPaddingHorizontal}px`,
textAlign: 'end',
background: token.modalFooterBg,
borderTop: `${token.modalFooterBorderWidth}px ${token.modalFooterBorderStyle} ${token.modalFooterBorderColorSplit}`,
borderRadius: `0 0 ${token.controlRadius}px ${token.controlRadius}px`,
[`${token.antCls}-btn + ${token.antCls}-btn:not(${token.antCls}-dropdown-trigger)`]: {
marginBottom: 0,
marginInlineStart: token.marginXS,
},
},
[`${componentCls}-open`]: {
overflow: 'hidden',
},
},
},
// ======================== Pure =========================
{
[`${componentCls}-pure-panel`]: {
top: 'auto',
padding: 0,
},
},
];
};
const genModalConfirmStyle: GenerateStyle<ModalToken> = token => {
const { componentCls } = token;
const confirmComponentCls = `${componentCls}-confirm`;
return {
[confirmComponentCls]: {
'&-rtl': {
direction: 'rtl',
},
[`${token.antCls}-modal-header`]: {
display: 'none',
},
[`${token.antCls}-modal-body`]: {
padding: `${token.padding * 2}px ${token.padding * 2}px ${token.paddingLG}px`,
},
[`${confirmComponentCls}-body-wrapper`]: {
...clearFix(),
},
[`${confirmComponentCls}-body`]: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
[`${confirmComponentCls}-title`]: {
flex: 1,
display: 'block',
// create BFC to avoid
// https://user-images.githubusercontent.com/507615/37702510-ba844e06-2d2d-11e8-9b67-8e19be57f445.png
overflow: 'hidden',
color: token.colorTextHeading,
fontWeight: token.fontWeightStrong,
fontSize: token.modalHeaderTitleFontSize,
lineHeight: token.modalHeaderTitleLineHeight,
},
[`${confirmComponentCls}-content`]: {
color: token.colorText,
fontSize: token.fontSizeBase,
},
[`> ${token.iconCls}`]: {
flex: 'none',
marginInlineEnd: token.margin,
fontSize: token.modalConfirmIconSize,
// `content` after `icon` should set marginLeft
[`+ ${confirmComponentCls}-title + ${confirmComponentCls}-content`]: {
marginInlineStart: token.modalConfirmIconSize + token.margin,
marginBlockStart: token.marginXS,
flexBasis: '100%',
},
},
},
[`${confirmComponentCls}-btns`]: {
textAlign: 'end',
marginTop: token.marginLG,
[`${token.antCls}-btn + ${token.antCls}-btn`]: {
marginBottom: 0,
marginInlineStart: token.marginXS,
},
},
},
[`${confirmComponentCls}-error ${confirmComponentCls}-body > ${token.iconCls}`]: {
color: token.colorError,
},
[`${confirmComponentCls}-warning ${confirmComponentCls}-body > ${token.iconCls},
${confirmComponentCls}-confirm ${confirmComponentCls}-body > ${token.iconCls}`]: {
color: token.colorWarning,
},
[`${confirmComponentCls}-info ${confirmComponentCls}-body > ${token.iconCls}`]: {
color: token.colorInfo,
},
[`${confirmComponentCls}-success ${confirmComponentCls}-body > ${token.iconCls}`]: {
color: token.colorSuccess,
},
};
};
const genRTLStyle: GenerateStyle<ModalToken> = token => {
const { componentCls } = token;
return {
[`${componentCls}-root`]: {
[`${componentCls}-wrap-rtl`]: {
direction: 'rtl',
[`${componentCls}-confirm-body`]: {
direction: 'rtl',
},
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Modal', token => {
const headerPaddingVertical = token.padding;
const headerFontSize = token.fontSizeHeading5;
const headerLineHeight = token.lineHeightHeading5;
const modalToken = mergeToken<ModalToken>(token, {
modalBodyPadding: token.paddingLG,
modalHeaderBg: token.colorBgElevated,
modalHeaderPadding: `${headerPaddingVertical}px ${token.paddingLG}px`,
modalHeaderBorderWidth: token.controlLineWidth,
modalHeaderBorderStyle: token.controlLineType,
modalHeaderTitleLineHeight: headerLineHeight,
modalHeaderTitleFontSize: headerFontSize,
modalHeaderBorderColorSplit: token.colorSplit,
modalHeaderCloseSize: headerLineHeight * headerFontSize + headerPaddingVertical * 2,
modalContentBg: token.colorBgElevated,
modalHeadingColor: token.colorTextHeading,
modalCloseColor: token.colorTextSecondary,
modalFooterBg: 'transparent',
modalFooterBorderColorSplit: token.colorSplit,
modalFooterBorderStyle: token.controlLineType,
modalFooterPaddingVertical: token.paddingXS,
modalFooterPaddingHorizontal: token.padding,
modalFooterBorderWidth: token.controlLineWidth,
modalConfirmTitleFontSize: token.fontSizeLG,
modalIconHoverColor: token.colorActionHover,
modalConfirmIconSize: token.fontSize * token.lineHeight,
});
return [
genModalStyle(modalToken),
genModalConfirmStyle(modalToken),
genRTLStyle(modalToken),
genModalMaskStyle(modalToken),
initZoomMotion(modalToken, 'zoom'),
];
});