ant-design/components/_util/theme/index.tsx

366 lines
9.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { generate } from '@ant-design/colors';
import { TinyColor } from '@ctrl/tinycolor';
import {
CSSInterpolation,
CSSObject,
Theme,
useCacheToken,
useStyleRegister,
} from '@ant-design/cssinjs';
import defaultDesignToken from './default';
import version from '../../version';
import { resetComponent, resetIcon, clearFix } from './util';
import {
initSlideMotion,
slideUpIn,
slideUpOut,
slideDownIn,
slideDownOut,
slideLeftIn,
slideLeftOut,
slideRightIn,
slideRightOut,
} from './util/slide';
export {
resetComponent,
resetIcon,
clearFix,
initSlideMotion,
slideUpIn,
slideUpOut,
slideDownIn,
slideDownOut,
slideLeftIn,
slideLeftOut,
slideRightIn,
slideRightOut,
};
export interface PresetColorType {
blue: string;
purple: string;
cyan: string;
green: string;
magenta: string;
pink: string;
red: string;
orange: string;
yellow: string;
volcano: string;
geekblue: string;
lime: string;
gold: string;
}
export const PresetColorKeys: ReadonlyArray<keyof PresetColorType> = [
'blue',
'purple',
'cyan',
'green',
'magenta',
'pink',
'red',
'orange',
'yellow',
'volcano',
'geekblue',
'lime',
'gold',
];
export interface DesignToken extends PresetColorType {
primaryColor: string;
successColor: string;
warningColor: string;
errorColor: string;
infoColor: string;
lineHeight: number;
borderWidth: number;
borderStyle: string;
borderRadius: number;
borderColor: string;
borderColorSplit: string;
easeInOut: string;
easeInOutCirc: string;
easeOutBack: string;
easeInQuint: string;
easeOutQuint: string;
outlineWidth: number;
outlineBlurSize: number;
fontSize: number;
fontFamily: string;
textColor: string;
textColorSecondary: string;
textColorDisabled: string;
textColorInverse: string;
placeholderColor: string;
disabledColor: string;
iconColorHover: string;
headingColor: string;
itemHoverBackground: string;
controlHeight: number;
padding: number;
margin: number;
background: string;
backgroundLight: string;
componentBackground: string;
componentBackgroundDisabled: string;
duration: number;
zIndexDropdown: number;
boxShadow?: string;
}
type ColorPaletteKeyIndexes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
type ColorPalettes = {
[key in `${keyof PresetColorType}-${ColorPaletteKeyIndexes[number]}`]: string;
};
/** This is temporary token definition since final token definition is not ready yet. */
export interface DerivativeToken extends ColorPalettes, Omit<DesignToken, 'duration'> {
primaryHoverColor: string;
primaryActiveColor: string;
primaryOutlineColor: string;
errorHoverColor: string;
errorActiveColor: string;
errorOutlineColor: string;
warningHoverColor: string;
warningOutlineColor: string;
itemActiveBackground: string;
2022-03-09 00:29:00 +08:00
highlightColor: string;
linkColor: string;
linkHoverColor: string;
linkActiveColor: string;
linkDecoration: CSSObject['textDecoration'];
linkHoverDecoration: CSSObject['textDecoration'];
linkFocusDecoration: CSSObject['textDecoration'];
fontSizeSM: number;
fontSizeLG: number;
/** @private Only Used for control inside component like Multiple Select inner selection item */
controlHeightXS: number;
controlHeightSM: number;
controlHeightLG: number;
controlPaddingHorizontal: number;
controlPaddingHorizontalSM: number;
paddingSM: number;
paddingXS: number;
paddingXXS: number;
paddingLG: number;
marginXS: number;
marginLG: number;
marginXXS: number;
duration: string;
durationMid: string;
durationFast: string;
heading1Size: number;
heading2Size: number;
heading3Size: number;
heading4Size: number;
heading5Size: number;
primaryColors: string[];
errorColors: string[];
warningColors: string[];
// TMP
tmpPrimaryColorWeak: string;
tmpPrimaryHoverColorWeak: string;
// Checked background for Checkable Tag
tmpPrimaryColor6: string;
// Active background for Checkable Tag
tmpPrimaryColor7: string;
tmpSuccessColorDeprecatedBg: string;
tmpWarningColorDeprecatedBg: string;
tmpErrorColorDeprecatedBg: string;
tmpInfoColorDeprecatedBg: string;
tmpSuccessColorDeprecatedBorder: string;
tmpWarningColorDeprecatedBorder: string;
tmpErrorColorDeprecatedBorder: string;
tmpInfoColorDeprecatedBorder: string;
}
export { useStyleRegister };
// =============================== Derivative ===============================
function derivative(designToken: DesignToken): DerivativeToken {
const { primaryColor, errorColor, warningColor, infoColor, successColor } = designToken;
const primaryColors = generate(primaryColor);
const errorColors = generate(errorColor);
const warningColors = generate(warningColor);
const infoColors = generate(infoColor);
const successColors = generate(successColor);
const paddingSM = (designToken.padding / 4) * 3;
const paddingXS = designToken.padding * 0.5;
const colorPalettes = PresetColorKeys.map((colorKey: keyof PresetColorType) => {
const colors = generate(designToken[colorKey]);
const ret = new Array(10).fill(1).reduce((prev, _, i) => {
prev[`${colorKey}-${i + 1}`] = colors[i];
return prev;
}, {}) as ColorPalettes;
return ret;
}).reduce((prev, cur) => {
prev = {
...prev,
...cur,
};
return prev;
}, {} as ColorPalettes);
return {
// FIXME: Need design token
boxShadow: `
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05)`,
...designToken,
primaryHoverColor: primaryColors[4],
primaryActiveColor: primaryColors[6],
primaryOutlineColor: new TinyColor(primaryColor).setAlpha(0.2).toRgbString(),
errorHoverColor: errorColors[4],
errorActiveColor: errorColors[6],
errorOutlineColor: new TinyColor(errorColor).setAlpha(0.2).toRgbString(),
warningHoverColor: warningColors[4],
warningOutlineColor: new TinyColor(warningColor).setAlpha(0.2).toRgbString(),
highlightColor: errorColors[5], // FIXME: Should not align with error color
// FIXME: fix2 badge-color
2022-03-09 00:29:00 +08:00
itemActiveBackground: primaryColors[0],
linkColor: primaryColor,
linkHoverColor: primaryColors[4],
linkActiveColor: primaryColors[6],
linkDecoration: 'none',
linkHoverDecoration: 'none',
linkFocusDecoration: 'none',
fontSizeSM: designToken.fontSize - 2,
fontSizeLG: designToken.fontSize + 2,
controlHeightXS: designToken.controlHeight / 2,
controlHeightSM: designToken.controlHeight * 0.75,
controlHeightLG: designToken.controlHeight * 1.25,
controlPaddingHorizontal: paddingSM,
controlPaddingHorizontalSM: paddingXS,
paddingSM,
paddingXS,
paddingXXS: designToken.padding * 0.25,
paddingLG: designToken.padding * 1.5,
marginXS: designToken.margin * 0.5,
marginLG: designToken.margin * 1.5,
marginXXS: designToken.margin * 0.25,
duration: `${designToken.duration}s`,
durationMid: `${(designToken.duration / 3) * 2}s`,
durationFast: `${designToken.duration / 3}s`,
...colorPalettes,
heading1Size: Math.ceil(designToken.fontSize * 2.71),
heading2Size: Math.ceil(designToken.fontSize * 2.14),
heading3Size: Math.ceil(designToken.fontSize * 1.71),
heading4Size: Math.ceil(designToken.fontSize * 1.42),
heading5Size: Math.ceil(designToken.fontSize * 1.14),
primaryColors,
errorColors,
warningColors,
// TMP
tmpPrimaryColorWeak: primaryColors[2],
tmpPrimaryHoverColorWeak: primaryColors[0],
tmpPrimaryColor6: primaryColors[5],
tmpPrimaryColor7: primaryColors[6],
tmpSuccessColorDeprecatedBg: successColors[0],
tmpWarningColorDeprecatedBg: warningColors[0],
tmpErrorColorDeprecatedBg: errorColors[0],
tmpInfoColorDeprecatedBg: infoColors[0],
tmpSuccessColorDeprecatedBorder: successColors[2],
tmpWarningColorDeprecatedBorder: warningColors[2],
tmpErrorColorDeprecatedBorder: errorColors[2],
tmpInfoColorDeprecatedBorder: infoColors[2],
};
}
// ================================ Context =================================
export const ThemeContext = React.createContext(
new Theme<DesignToken, DerivativeToken>(derivative),
);
export const DesignTokenContext = React.createContext<{
token: Partial<DesignToken>;
hashed?: string | boolean;
}>({
token: defaultDesignToken,
});
// ================================== Hook ==================================
export function useToken(): [Theme<DesignToken, DerivativeToken>, DerivativeToken, string] {
const { token: rootDesignToken, hashed } = React.useContext(DesignTokenContext);
const theme = React.useContext(ThemeContext);
const salt = `${version}-${hashed || ''}`;
const [token, hashId] = useCacheToken<DerivativeToken, DesignToken>(
theme,
[defaultDesignToken, rootDesignToken],
{
salt,
},
);
2022-02-27 22:17:17 +08:00
return [theme, token, hashed ? hashId : ''];
}
export type UseComponentStyleResult = [(node: React.ReactNode) => React.ReactElement, string];
export type GenerateStyle<ComponentToken extends object, ReturnType = CSSInterpolation> = (
token: ComponentToken,
hashId?: string,
) => ReturnType;
// ================================== Util ==================================
export function withPrefix(
style: CSSObject,
prefixCls: string,
additionalClsList: string[] = [],
): CSSObject {
const fullClsList = [prefixCls, ...additionalClsList].filter(cls => cls).map(cls => `.${cls}`);
return {
[fullClsList.join('')]: style,
};
}