2022-04-02 22:55:02 +08:00
|
|
|
/* eslint-disable no-redeclare */
|
2023-08-28 21:42:39 +08:00
|
|
|
import { useContext, type ComponentType } from 'react';
|
2022-05-09 22:20:07 +08:00
|
|
|
import type { CSSInterpolation } from '@ant-design/cssinjs';
|
|
|
|
import { useStyleRegister } from '@ant-design/cssinjs';
|
2023-05-18 21:18:02 +08:00
|
|
|
import { warning } from 'rc-util';
|
2023-08-27 23:48:56 +08:00
|
|
|
|
2022-06-27 14:25:59 +08:00
|
|
|
import { ConfigContext } from '../../config-provider/context';
|
2023-03-27 23:00:56 +08:00
|
|
|
import { genCommonStyle, genLinkStyle } from '../../style';
|
2023-06-06 17:44:30 +08:00
|
|
|
import type {
|
|
|
|
ComponentTokenMap,
|
|
|
|
GlobalToken,
|
|
|
|
OverrideToken,
|
|
|
|
UseComponentStyleResult,
|
|
|
|
} from '../interface';
|
|
|
|
import useToken from '../useToken';
|
|
|
|
import statisticToken, { merge as mergeToken } from './statistic';
|
2023-08-28 10:49:18 +08:00
|
|
|
import useResetIconStyle from './useResetIconStyle';
|
2022-04-02 22:55:02 +08:00
|
|
|
|
2022-06-27 11:54:31 +08:00
|
|
|
export type OverrideTokenWithoutDerivative = ComponentTokenMap;
|
2022-04-02 22:55:02 +08:00
|
|
|
export type OverrideComponent = keyof OverrideTokenWithoutDerivative;
|
|
|
|
export type GlobalTokenWithComponent<ComponentName extends OverrideComponent> = GlobalToken &
|
2022-06-27 11:54:31 +08:00
|
|
|
ComponentTokenMap[ComponentName];
|
2022-04-25 10:54:00 +08:00
|
|
|
|
2023-05-18 21:18:02 +08:00
|
|
|
type ComponentToken<ComponentName extends OverrideComponent> = Exclude<
|
2023-05-23 13:39:05 +08:00
|
|
|
OverrideToken[ComponentName],
|
2023-05-18 21:18:02 +08:00
|
|
|
undefined
|
|
|
|
>;
|
|
|
|
type ComponentTokenKey<ComponentName extends OverrideComponent> =
|
|
|
|
keyof ComponentToken<ComponentName>;
|
|
|
|
|
2022-09-19 22:17:26 +08:00
|
|
|
export interface StyleInfo<ComponentName extends OverrideComponent> {
|
2022-04-02 22:55:02 +08:00
|
|
|
hashId: string;
|
|
|
|
prefixCls: string;
|
|
|
|
rootPrefixCls: string;
|
|
|
|
iconPrefixCls: string;
|
2022-09-19 22:17:26 +08:00
|
|
|
overrideComponentToken: ComponentTokenMap[ComponentName];
|
2022-04-25 10:54:00 +08:00
|
|
|
}
|
|
|
|
|
2022-04-07 00:19:37 +08:00
|
|
|
export type TokenWithCommonCls<T> = T & {
|
2022-04-25 10:54:00 +08:00
|
|
|
/** Wrap component class with `.` prefix */
|
2022-04-06 12:20:52 +08:00
|
|
|
componentCls: string;
|
2022-04-25 10:54:00 +08:00
|
|
|
/** Origin prefix which do not have `.` prefix */
|
2022-04-06 12:20:52 +08:00
|
|
|
prefixCls: string;
|
2022-04-25 10:54:00 +08:00
|
|
|
/** Wrap icon class with `.` prefix */
|
2022-04-06 12:20:52 +08:00
|
|
|
iconCls: string;
|
2022-04-25 10:54:00 +08:00
|
|
|
/** Wrap ant prefixCls class with `.` prefix */
|
2022-04-07 00:19:37 +08:00
|
|
|
antCls: string;
|
2022-04-06 12:20:52 +08:00
|
|
|
};
|
2022-04-07 00:19:37 +08:00
|
|
|
export type FullToken<ComponentName extends OverrideComponent> = TokenWithCommonCls<
|
2022-04-02 22:55:02 +08:00
|
|
|
GlobalTokenWithComponent<ComponentName>
|
|
|
|
>;
|
|
|
|
|
2023-08-27 23:48:56 +08:00
|
|
|
export type GenStyleFn<ComponentName extends OverrideComponent> = (
|
|
|
|
token: FullToken<ComponentName>,
|
|
|
|
info: StyleInfo<ComponentName>,
|
|
|
|
) => CSSInterpolation;
|
|
|
|
|
2022-05-17 18:39:13 +08:00
|
|
|
export default function genComponentStyleHook<ComponentName extends OverrideComponent>(
|
2023-08-27 23:48:56 +08:00
|
|
|
componentName: ComponentName | [ComponentName, string],
|
|
|
|
styleFn: GenStyleFn<ComponentName>,
|
2022-04-02 22:55:02 +08:00
|
|
|
getDefaultToken?:
|
2023-08-29 15:48:03 +08:00
|
|
|
| null
|
2022-04-02 22:55:02 +08:00
|
|
|
| OverrideTokenWithoutDerivative[ComponentName]
|
|
|
|
| ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName]),
|
2023-08-29 15:48:03 +08:00
|
|
|
options: {
|
2023-04-10 10:29:26 +08:00
|
|
|
resetStyle?: boolean;
|
2023-05-18 21:18:02 +08:00
|
|
|
// Deprecated token key map [["oldTokenKey", "newTokenKey"], ["oldTokenKey", "newTokenKey"]]
|
|
|
|
deprecatedTokens?: [ComponentTokenKey<ComponentName>, ComponentTokenKey<ComponentName>][];
|
2023-07-26 11:03:42 +08:00
|
|
|
/**
|
|
|
|
* Only use component style in client side. Ignore in SSR.
|
|
|
|
*/
|
|
|
|
clientOnly?: boolean;
|
2023-08-29 15:48:03 +08:00
|
|
|
/**
|
|
|
|
* Set order of component style. Default is -999.
|
|
|
|
*/
|
|
|
|
order?: number;
|
|
|
|
} = {},
|
2022-04-02 22:55:02 +08:00
|
|
|
) {
|
2023-08-27 23:48:56 +08:00
|
|
|
const cells = (Array.isArray(componentName) ? componentName : [componentName, componentName]) as [
|
|
|
|
ComponentName,
|
|
|
|
string,
|
|
|
|
];
|
|
|
|
|
|
|
|
const [component] = cells;
|
|
|
|
const concatComponent = cells.join('-');
|
|
|
|
|
2022-04-02 22:55:02 +08:00
|
|
|
return (prefixCls: string): UseComponentStyleResult => {
|
|
|
|
const [theme, token, hashId] = useToken();
|
2023-03-27 23:00:56 +08:00
|
|
|
const { getPrefixCls, iconPrefixCls, csp } = useContext(ConfigContext);
|
2022-04-07 00:19:37 +08:00
|
|
|
const rootPrefixCls = getPrefixCls();
|
2022-04-02 22:55:02 +08:00
|
|
|
|
2023-03-27 23:00:56 +08:00
|
|
|
// Shared config
|
|
|
|
const sharedConfig: Omit<Parameters<typeof useStyleRegister>[0], 'path'> = {
|
|
|
|
theme,
|
|
|
|
token,
|
|
|
|
hashId,
|
|
|
|
nonce: () => csp?.nonce!,
|
2023-08-29 15:48:03 +08:00
|
|
|
clientOnly: options.clientOnly,
|
2023-07-27 16:07:48 +08:00
|
|
|
|
|
|
|
// antd is always at top of styles
|
2023-08-29 15:48:03 +08:00
|
|
|
order: options.order || -999,
|
2023-03-27 23:00:56 +08:00
|
|
|
};
|
|
|
|
|
2022-07-13 18:08:03 +08:00
|
|
|
// Generate style for all a tags in antd component.
|
2023-07-28 11:17:29 +08:00
|
|
|
useStyleRegister(
|
|
|
|
{ ...sharedConfig, clientOnly: false, path: ['Shared', rootPrefixCls] },
|
|
|
|
() => [
|
|
|
|
{
|
|
|
|
// Link
|
|
|
|
'&': genLinkStyle(token),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
);
|
2022-07-13 18:08:03 +08:00
|
|
|
|
2023-08-28 10:49:18 +08:00
|
|
|
// Generate style for icons
|
2023-10-13 23:14:49 +08:00
|
|
|
useResetIconStyle(iconPrefixCls, csp);
|
2023-08-28 10:49:18 +08:00
|
|
|
|
2022-04-02 22:55:02 +08:00
|
|
|
return [
|
2023-08-27 23:48:56 +08:00
|
|
|
useStyleRegister(
|
|
|
|
{ ...sharedConfig, path: [concatComponent, prefixCls, iconPrefixCls] },
|
|
|
|
() => {
|
|
|
|
const { token: proxyToken, flush } = statisticToken(token);
|
|
|
|
|
|
|
|
const customComponentToken = { ...(token[component] as ComponentToken<ComponentName>) };
|
2023-08-29 15:48:03 +08:00
|
|
|
if (options.deprecatedTokens) {
|
2023-08-27 23:48:56 +08:00
|
|
|
const { deprecatedTokens } = options;
|
|
|
|
deprecatedTokens.forEach(([oldTokenKey, newTokenKey]) => {
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
warning(
|
|
|
|
!customComponentToken?.[oldTokenKey],
|
|
|
|
`The token '${String(oldTokenKey)}' of ${component} had deprecated, use '${String(
|
|
|
|
newTokenKey,
|
|
|
|
)}' instead.`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should wrap with `if` clause, or there will be `undefined` in object.
|
|
|
|
if (customComponentToken?.[oldTokenKey] || customComponentToken?.[newTokenKey]) {
|
|
|
|
customComponentToken[newTokenKey] ??= customComponentToken?.[oldTokenKey];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
const defaultComponentToken =
|
|
|
|
typeof getDefaultToken === 'function'
|
|
|
|
? getDefaultToken(mergeToken(proxyToken, customComponentToken ?? {}))
|
|
|
|
: getDefaultToken;
|
|
|
|
|
|
|
|
const mergedComponentToken = { ...defaultComponentToken, ...customComponentToken };
|
|
|
|
|
|
|
|
const componentCls = `.${prefixCls}`;
|
|
|
|
const mergedToken = mergeToken<
|
|
|
|
TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>
|
|
|
|
>(
|
|
|
|
proxyToken,
|
|
|
|
{
|
|
|
|
componentCls,
|
|
|
|
prefixCls,
|
|
|
|
iconCls: `.${iconPrefixCls}`,
|
|
|
|
antCls: `.${rootPrefixCls}`,
|
|
|
|
},
|
|
|
|
mergedComponentToken,
|
|
|
|
);
|
|
|
|
|
|
|
|
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
|
|
|
|
hashId,
|
2022-08-26 19:31:53 +08:00
|
|
|
prefixCls,
|
2023-08-27 23:48:56 +08:00
|
|
|
rootPrefixCls,
|
|
|
|
iconPrefixCls,
|
|
|
|
overrideComponentToken: customComponentToken as any,
|
|
|
|
});
|
|
|
|
flush(component, mergedComponentToken);
|
|
|
|
return [
|
2023-11-08 16:27:50 +08:00
|
|
|
options.resetStyle === false ? null : genCommonStyle(mergedToken, prefixCls),
|
2023-08-27 23:48:56 +08:00
|
|
|
styleInterpolation,
|
|
|
|
];
|
|
|
|
},
|
|
|
|
),
|
2022-04-02 22:55:02 +08:00
|
|
|
hashId,
|
|
|
|
];
|
|
|
|
};
|
|
|
|
}
|
2023-08-28 21:42:39 +08:00
|
|
|
|
|
|
|
export interface SubStyleComponentProps {
|
|
|
|
prefixCls: string;
|
|
|
|
}
|
|
|
|
|
2023-08-31 22:21:32 +08:00
|
|
|
// Get from second argument
|
|
|
|
type RestParameters<T extends any[]> = T extends [any, ...infer Rest] ? Rest : never;
|
|
|
|
|
2023-08-29 19:43:48 +08:00
|
|
|
export const genSubStyleComponent: <ComponentName extends OverrideComponent>(
|
2023-08-31 22:21:32 +08:00
|
|
|
componentName: [ComponentName, string],
|
|
|
|
...args: RestParameters<Parameters<typeof genComponentStyleHook<ComponentName>>>
|
2023-08-29 19:43:48 +08:00
|
|
|
) => ComponentType<SubStyleComponentProps> = (componentName, styleFn, getDefaultToken, options) => {
|
|
|
|
const useStyle = genComponentStyleHook(componentName, styleFn, getDefaultToken, {
|
|
|
|
resetStyle: false,
|
|
|
|
|
|
|
|
// Sub Style should default after root one
|
|
|
|
order: -998,
|
|
|
|
...options,
|
|
|
|
});
|
2023-08-28 21:42:39 +08:00
|
|
|
|
2023-08-31 22:21:32 +08:00
|
|
|
const StyledComponent: ComponentType<SubStyleComponentProps> = ({
|
|
|
|
prefixCls,
|
|
|
|
}: SubStyleComponentProps) => {
|
2023-08-28 21:42:39 +08:00
|
|
|
useStyle(prefixCls);
|
|
|
|
return null;
|
|
|
|
};
|
2023-08-31 22:21:32 +08:00
|
|
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
StyledComponent.displayName = `SubStyle_${
|
|
|
|
Array.isArray(componentName) ? componentName.join('.') : componentName
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return StyledComponent;
|
2023-08-29 19:43:48 +08:00
|
|
|
};
|