diff --git a/.jest.image.js b/.jest.image.js index 78191c45d4..8038d666d8 100644 --- a/.jest.image.js +++ b/.jest.image.js @@ -1,13 +1,11 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); -// jest config for image snapshots module.exports = { setupFiles: ['./tests/setup.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], moduleNameMapper, transform: { - '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', - '\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '^.+\\.(ts|tsx|js|mjs)$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', }, diff --git a/.jest.js b/.jest.js index 3a431c0f34..20a17166c0 100644 --- a/.jest.js +++ b/.jest.js @@ -11,6 +11,7 @@ const compileModules = [ 'parse5', '@exodus', 'jsdom', + '@csstools', ]; // cnpm use `_` as prefix @@ -62,7 +63,7 @@ module.exports = { ], transform: { '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', - '\\.(m?)js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '\\.(m?)js(m)?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', }, diff --git a/.jest.node.js b/.jest.node.js index e4631d406e..aad21544be 100644 --- a/.jest.node.js +++ b/.jest.node.js @@ -1,14 +1,12 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); -// jest config for server render environment module.exports = { setupFiles: ['./tests/setup.ts'], setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], moduleNameMapper, transform: { - '\\.tsx?$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', - '\\.js$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', + '^.+\\.(ts|tsx|js|mjs)$': './node_modules/@ant-design/tools/lib/jest/codePreprocessor', '\\.md$': './node_modules/@ant-design/tools/lib/jest/demoPreprocessor', '\\.(jpg|png|gif|svg)$': './node_modules/@ant-design/tools/lib/jest/imagePreprocessor', }, diff --git a/components/button/style/token.ts b/components/button/style/token.ts index dedb914ee9..e12a92e204 100644 --- a/components/button/style/token.ts +++ b/components/button/style/token.ts @@ -4,9 +4,9 @@ import { unit } from '@ant-design/cssinjs'; import { AggregationColor } from '../../color-picker/color'; import { isBright } from '../../color-picker/components/ColorPresets'; +import { PresetColors } from '../../theme/interface'; import type { FullToken, GenStyleFn, GetDefaultToken, PresetColorKey } from '../../theme/internal'; import { getLineHeight, mergeToken } from '../../theme/internal'; -import { PresetColors } from '../../theme/interface'; import getAlphaColor from '../../theme/util/getAlphaColor'; /** Component only token. Which will handle additional calculation of alias token */ @@ -247,6 +247,10 @@ type ShadowColorMap = { [Key in `${PresetColorKey}ShadowColor`]: string; }; +type PresetColorHoverActiveMap = { + [Key in `${PresetColorKey}Hover` | `${PresetColorKey}Active`]: string; +}; + type GroupToken = { /** * @desc 按钮组边框颜色 @@ -257,7 +261,11 @@ type GroupToken = { groupBorderColor: string; }; -export interface ButtonToken extends FullToken<'Button'>, ShadowColorMap, GroupToken { +export interface ButtonToken + extends FullToken<'Button'>, + ShadowColorMap, + PresetColorHoverActiveMap, + GroupToken { /** * @desc 按钮横向内边距 * @descEN Horizontal padding of button diff --git a/components/button/style/variant.ts b/components/button/style/variant.ts index 7f3237bb5a..40fe3fa781 100644 --- a/components/button/style/variant.ts +++ b/components/button/style/variant.ts @@ -268,10 +268,10 @@ const genVariantStyle: GenerateStyle = (token) => { PresetColors.map((colorKey) => { const darkColor = token[`${colorKey}6`]; const lightColor = token[`${colorKey}1`]; - const hoverColor = token[`${colorKey}5`]; + const hoverColor = token[`${colorKey}Hover`]; const lightHoverColor = token[`${colorKey}2`]; const lightActiveColor = token[`${colorKey}3`]; - const activeColor = token[`${colorKey}7`]; + const activeColor = token[`${colorKey}Active`]; const shadowColor = token[`${colorKey}ShadowColor`]; diff --git a/components/modal/__tests__/confirm.test.tsx b/components/modal/__tests__/confirm.test.tsx index 50074e7fae..f99c844a24 100644 --- a/components/modal/__tests__/confirm.test.tsx +++ b/components/modal/__tests__/confirm.test.tsx @@ -678,6 +678,8 @@ describe('Modal.confirm triggers callbacks correctly', () => { describe('the callback close should be a method when onCancel has a close parameter', () => { (['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => { it(`click the close icon to trigger ${type} onCancel`, async () => { + jest.useFakeTimers(); + const mock = jest.fn(); Modal[type]?.({ @@ -688,17 +690,21 @@ describe('Modal.confirm triggers callbacks correctly', () => { await waitFakeTimer(); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1); - $$('.ant-modal-close')[0].click(); + fireEvent.click($$('.ant-modal-close')[0]); await waitFakeTimer(); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0); expect(mock).toHaveBeenCalledWith(expect.any(Function)); + + jest.useRealTimers(); }); }); (['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => { it(`press ESC to trigger ${type} onCancel`, async () => { + jest.useFakeTimers(); + const mock = jest.fn(); Modal[type]?.({ @@ -709,17 +715,21 @@ describe('Modal.confirm triggers callbacks correctly', () => { await waitFakeTimer(); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1); - fireEvent.keyDown(window, { key: 'Escape' }); + fireEvent.keyDown($$(`.ant-modal-confirm-${type}`)[0], { key: 'Escape' }); await waitFakeTimer(0); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0); expect(mock).toHaveBeenCalledWith(expect.any(Function)); + + jest.useRealTimers(); }); }); (['confirm', 'info', 'success', 'warning', 'error'] as const).forEach((type) => { it(`click the mask to trigger ${type} onCancel`, async () => { + jest.useFakeTimers(); + const mock = jest.fn(); Modal[type]?.({ @@ -732,17 +742,22 @@ describe('Modal.confirm triggers callbacks correctly', () => { expect($$('.ant-modal-mask')).toHaveLength(1); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1); - $$('.ant-modal-wrap')[0].click(); + fireEvent.mouseDown($$('.ant-modal-wrap')[0]); + fireEvent.click($$('.ant-modal-wrap')[0]); await waitFakeTimer(); expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0); expect(mock).toHaveBeenCalledWith(expect.any(Function)); + + jest.useRealTimers(); }); }); }); it('confirm modal click Cancel button close callback is a function', async () => { + jest.useFakeTimers(); + const mock = jest.fn(); Modal.confirm({ @@ -751,13 +766,17 @@ describe('Modal.confirm triggers callbacks correctly', () => { await waitFakeTimer(); - $$('.ant-modal-confirm-btns > .ant-btn')[0].click(); + fireEvent.click($$('.ant-modal-confirm-btns > .ant-btn')[0]); await waitFakeTimer(); expect(mock).toHaveBeenCalledWith(expect.any(Function)); + + jest.useRealTimers(); }); it('close can close modal when onCancel has a close parameter', async () => { + jest.useFakeTimers(); + Modal.confirm({ onCancel: (close) => close(), }); @@ -766,10 +785,12 @@ describe('Modal.confirm triggers callbacks correctly', () => { expect($$('.ant-modal-confirm-confirm')).toHaveLength(1); - $$('.ant-modal-confirm-btns > .ant-btn')[0].click(); + fireEvent.click($$('.ant-modal-confirm-btns > .ant-btn')[0]); await waitFakeTimer(); expect($$('.ant-modal-confirm-confirm')).toHaveLength(0); + + jest.useRealTimers(); }); // https://github.com/ant-design/ant-design/issues/37461 diff --git a/components/modal/__tests__/hook.test.tsx b/components/modal/__tests__/hook.test.tsx index 11c1301bd6..585387feb6 100644 --- a/components/modal/__tests__/hook.test.tsx +++ b/components/modal/__tests__/hook.test.tsx @@ -186,6 +186,7 @@ describe('Modal.hook', () => { expect(cancelCount).toEqual(1); // click cancel btn, trigger onCancel fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]); + fireEvent.mouseDown(document.body.querySelectorAll('.ant-modal-wrap')[0]); fireEvent.click(document.body.querySelectorAll('.ant-modal-wrap')[0]); expect(cancelCount).toEqual(2); // click modal wrapper, trigger onCancel }); @@ -360,6 +361,7 @@ describe('Modal.hook', () => { expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1); // Click mask to close + fireEvent.mouseDown(document.body.querySelectorAll('.ant-modal-wrap')[0]); fireEvent.click(document.body.querySelectorAll('.ant-modal-wrap')[0]); await waitFakeTimer(); diff --git a/components/theme/themes/dark/index.ts b/components/theme/themes/dark/index.ts index 746905a318..56d8441bcb 100644 --- a/components/theme/themes/dark/index.ts +++ b/components/theme/themes/dark/index.ts @@ -2,6 +2,7 @@ import { generate } from '@ant-design/colors'; import type { DerivativeFunc } from '@ant-design/cssinjs'; import type { MapToken, PresetColorType, SeedToken } from '../../interface'; +import { PresetColors } from '../../interface/presetColors'; import defaultAlgorithm from '../default'; import { defaultPresetColors } from '../seed'; import genColorMapToken from '../shared/genColorMapToken'; @@ -29,6 +30,19 @@ const derivative: DerivativeFunc = (token, mapToken) => { generateNeutralColorPalettes, }); + const presetColorHoverActiveTokens = PresetColors.reduce>( + (prev, colorKey) => { + const colorBase = token[colorKey as keyof PresetColorType]; + if (colorBase) { + const colorPalette = generateColorPalettes(colorBase); + prev[`${colorKey}Hover`] = colorPalette[7]; + prev[`${colorKey}Active`] = colorPalette[5]; + } + return prev; + }, + {}, + ); + return { ...mergedMapToken, @@ -38,6 +52,8 @@ const derivative: DerivativeFunc = (token, mapToken) => { // Colors ...colorMapToken, + ...presetColorHoverActiveTokens, + // Customize selected item background color // https://github.com/ant-design/ant-design/issues/30524#issuecomment-871961867 colorPrimaryBg: colorMapToken.colorPrimaryBorder, diff --git a/components/theme/themes/shared/genColorMapToken.ts b/components/theme/themes/shared/genColorMapToken.ts index bfc96efb3a..aef704624e 100644 --- a/components/theme/themes/shared/genColorMapToken.ts +++ b/components/theme/themes/shared/genColorMapToken.ts @@ -1,6 +1,7 @@ import { FastColor } from '@ant-design/fast-color'; import type { ColorMapToken, SeedToken } from '../../interface'; +import { PresetColors } from '../../interface/presetColors'; import type { GenerateColorMap, GenerateNeutralColorMap } from '../ColorMap'; interface PaletteGenerators { @@ -37,6 +38,16 @@ export default function genColorMapToken( .mix(new FastColor(errorColors[3]), 50) .toHexString(); + const presetColorTokens: Record = {}; + PresetColors.forEach((colorKey) => { + const colorBase = seed[colorKey]; + if (colorBase) { + const colorPalette = generateColorPalettes(colorBase); + presetColorTokens[`${colorKey}Hover`] = colorPalette[5]; + presetColorTokens[`${colorKey}Active`] = colorPalette[7]; + } + }); + return { ...neutralColors, @@ -101,6 +112,8 @@ export default function genColorMapToken( colorLink: linkColors[6], colorLinkActive: linkColors[7], + ...presetColorTokens, + colorBgMask: new FastColor('#000').setA(0.45).toRgbString(), colorWhite: '#fff', }; diff --git a/package.json b/package.json index 084fbae87a..8a187efb64 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "@rc-component/tree-select": "~1.8.0", "@rc-component/trigger": "^3.9.0", "@rc-component/upload": "~1.1.0", - "@rc-component/util": "^1.8.1", + "@rc-component/util": "^1.8.2", "clsx": "^2.1.1", "dayjs": "^1.11.11", "scroll-into-view-if-needed": "^3.1.0",