/* eslint-disable no-redeclare */ import type { CSSInterpolation } from '@ant-design/cssinjs'; import { useStyleRegister } from '@ant-design/cssinjs'; import { warning } from 'rc-util'; import { useContext } from 'react'; import { ConfigContext } from '../../config-provider/context'; import { genCommonStyle, genLinkStyle } from '../../style'; import type { ComponentTokenMap, GlobalToken, OverrideToken } from '../interface'; import type { UseComponentStyleResult } from '../internal'; import { mergeToken, statisticToken, useToken } from '../internal'; export type OverrideTokenWithoutDerivative = ComponentTokenMap; export type OverrideComponent = keyof OverrideTokenWithoutDerivative; export type GlobalTokenWithComponent = GlobalToken & ComponentTokenMap[ComponentName]; type ComponentToken = Exclude< OverrideToken[ComponentName], undefined >; type ComponentTokenKey = keyof ComponentToken; export interface StyleInfo { hashId: string; prefixCls: string; rootPrefixCls: string; iconPrefixCls: string; overrideComponentToken: ComponentTokenMap[ComponentName]; } export type TokenWithCommonCls = T & { /** Wrap component class with `.` prefix */ componentCls: string; /** Origin prefix which do not have `.` prefix */ prefixCls: string; /** Wrap icon class with `.` prefix */ iconCls: string; /** Wrap ant prefixCls class with `.` prefix */ antCls: string; }; export type FullToken = TokenWithCommonCls< GlobalTokenWithComponent >; export default function genComponentStyleHook( component: ComponentName, styleFn: (token: FullToken, info: StyleInfo) => CSSInterpolation, getDefaultToken?: | OverrideTokenWithoutDerivative[ComponentName] | ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName]), options?: { resetStyle?: boolean; // Deprecated token key map [["oldTokenKey", "newTokenKey"], ["oldTokenKey", "newTokenKey"]] deprecatedTokens?: [ComponentTokenKey, ComponentTokenKey][]; }, ) { return (prefixCls: string): UseComponentStyleResult => { const [theme, token, hashId] = useToken(); const { getPrefixCls, iconPrefixCls, csp } = useContext(ConfigContext); const rootPrefixCls = getPrefixCls(); // Shared config const sharedConfig: Omit[0], 'path'> = { theme, token, hashId, nonce: () => csp?.nonce!, }; // Generate style for all a tags in antd component. useStyleRegister({ ...sharedConfig, path: ['Shared', rootPrefixCls] }, () => [ { // Link '&': genLinkStyle(token), }, ]); return [ useStyleRegister({ ...sharedConfig, path: [component, prefixCls, iconPrefixCls] }, () => { const { token: proxyToken, flush } = statisticToken(token); const customComponentToken = token[component] as ComponentToken; const defaultComponentToken = typeof getDefaultToken === 'function' ? getDefaultToken(mergeToken(proxyToken, customComponentToken ?? {})) : getDefaultToken; const mergedComponentToken = { ...defaultComponentToken, ...customComponentToken }; if (options?.deprecatedTokens) { 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.`, ); } mergedComponentToken[newTokenKey] = customComponentToken?.[newTokenKey] || customComponentToken?.[oldTokenKey] || defaultComponentToken[newTokenKey]; }); } const componentCls = `.${prefixCls}`; const mergedToken = mergeToken< TokenWithCommonCls> >( proxyToken, { componentCls, prefixCls, iconCls: `.${iconPrefixCls}`, antCls: `.${rootPrefixCls}`, }, mergedComponentToken, ); const styleInterpolation = styleFn(mergedToken as unknown as FullToken, { hashId, prefixCls, rootPrefixCls, iconPrefixCls, overrideComponentToken: token[component], }); flush(component, mergedComponentToken); return [ options?.resetStyle === false ? null : genCommonStyle(token, prefixCls), styleInterpolation, ]; }), hashId, ]; }; }