diff --git a/src/UniqueProvider/index.tsx b/src/UniqueProvider/index.tsx index 7f7625d1..55403f74 100644 --- a/src/UniqueProvider/index.tsx +++ b/src/UniqueProvider/index.tsx @@ -15,6 +15,7 @@ import { isDOM } from '@rc-component/util/lib/Dom/findDOMNode'; import FloatBg from './FloatBg'; import classNames from 'classnames'; import MotionContent from './MotionContent'; +import { getAlignPopupClassName } from '../util'; export interface UniqueProviderProps { children: React.ReactNode; @@ -93,6 +94,26 @@ const UniqueProvider = ({ children }: UniqueProviderProps) => { false, // isMobile ); + const alignedClassName = React.useMemo(() => { + if (!options) { + return ''; + } + + const baseClassName = getAlignPopupClassName( + options.builtinPlacements || {}, + options.prefixCls || '', + alignInfo, + false, // alignPoint is false for UniqueProvider + ); + + return classNames(baseClassName, options.getPopupClassNameFromAlign?.(alignInfo)); + }, [ + alignInfo, + options?.getPopupClassNameFromAlign, + options?.builtinPlacements, + options?.prefixCls, + ]); + const contextValue = React.useMemo( () => ({ show, @@ -141,6 +162,7 @@ const UniqueProvider = ({ children }: UniqueProviderProps) => { } className={classNames( options.popupClassName, + alignedClassName, `${prefixCls}-unique-controlled`, )} style={options.popupStyle} diff --git a/src/context.ts b/src/context.ts index 98b77e3a..54f92103 100644 --- a/src/context.ts +++ b/src/context.ts @@ -31,6 +31,7 @@ export interface UniqueShowOptions { maskMotion?: CSSMotionProps; arrow?: ArrowTypeOuter; getPopupContainer?: TriggerProps['getPopupContainer']; + getPopupClassNameFromAlign?: (align: AlignType) => string; } export interface UniqueContextProps { diff --git a/src/index.tsx b/src/index.tsx index 6cc2aa4a..945b9733 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -331,6 +331,7 @@ export function generateTrigger( maskMotion, arrow: innerArrow, getPopupContainer, + getPopupClassNameFromAlign, id, })); diff --git a/tests/unique.test.tsx b/tests/unique.test.tsx index e5e5e300..0174becf 100644 --- a/tests/unique.test.tsx +++ b/tests/unique.test.tsx @@ -103,4 +103,56 @@ describe('Trigger.Unique', () => { // FloatBg open prop should not have changed during transition (no close animation) expect(global.openChangeLog).toHaveLength(0); }); + + it('should add aligned className to UniqueProvider popup', async () => { + const getPopupClassNameFromAlign = (align: any) => { + return `custom-align-${align.points?.[0] || 'default'}`; + }; + + const { container } = render( + + tooltip} + unique + popupPlacement="bottomLeft" + builtinPlacements={{ + bottomLeft: { + points: ['tl', 'bl'], + offset: [0, 4], + overflow: { + adjustX: 0, + adjustY: 1, + }, + }, + }} + getPopupClassNameFromAlign={getPopupClassNameFromAlign} + > +
click me
+
+
, + ); + + // Initially no popup should be visible + expect(document.querySelector('.rc-trigger-popup')).toBeFalsy(); + + // Click trigger to show popup + fireEvent.click(container.querySelector('.target')); + await awaitFakeTimer(); + + // Wait a bit more for alignment to complete + await awaitFakeTimer(); + + // Check that popup exists + const popup = document.querySelector('.rc-trigger-popup'); + expect(popup).toBeTruthy(); + expect(popup.querySelector('.x-content').textContent).toBe('tooltip'); + + // Check that custom className from getPopupClassNameFromAlign is applied + expect(popup.className).toContain('custom-align'); + expect(popup.className).toContain('rc-trigger-popup-unique-controlled'); + + // The base placement className might not be available immediately due to async alignment + // but the custom className should always be applied + }); });