diff --git a/src/UniqueProvider/index.tsx b/src/UniqueProvider/index.tsx index 7ad3b3d7..342b14ce 100644 --- a/src/UniqueProvider/index.tsx +++ b/src/UniqueProvider/index.tsx @@ -22,7 +22,10 @@ export interface UniqueProviderProps { postTriggerProps?: (options: UniqueShowOptions) => UniqueShowOptions; } -const UniqueProvider = ({ children, postTriggerProps }: UniqueProviderProps) => { +const UniqueProvider = ({ + children, + postTriggerProps, +}: UniqueProviderProps) => { const [trigger, open, options, onTargetVisibleChanged] = useTargetState(); // ========================== Options =========================== @@ -144,6 +147,11 @@ const UniqueProvider = ({ children, postTriggerProps }: UniqueProviderProps) => [], ); + // =========================== Align ============================ + React.useEffect(() => { + onAlign(); + }, [mergedOptions?.target]); + // =========================== Motion =========================== const onPrepare = useEvent(() => { onAlign(); diff --git a/tests/unique.test.tsx b/tests/unique.test.tsx index a5ff3c9c..2450ed4d 100644 --- a/tests/unique.test.tsx +++ b/tests/unique.test.tsx @@ -66,6 +66,7 @@ describe('Trigger.Unique', () => { afterEach(() => { cleanup(); jest.useRealTimers(); + jest.restoreAllMocks(); }); it('moving will not hide the popup', async () => { @@ -285,4 +286,82 @@ describe('Trigger.Unique', () => { 'custom-post-options-class', ); }); + + it('should call onAlign when target changes', async () => { + const mockOnAlign = jest.fn(); + + // Mock useAlign to return our mock onAlign function + const useAlignModule = require('../src/hooks/useAlign'); + const originalUseAlign = useAlignModule.default; + + jest.spyOn(useAlignModule, 'default').mockImplementation((...args) => { + const originalResult = originalUseAlign(...args); + // Replace onAlign with our mock + return [ + originalResult[0], // ready + originalResult[1], // offsetX + originalResult[2], // offsetY + originalResult[3], // offsetR + originalResult[4], // offsetB + originalResult[5], // arrowX + originalResult[6], // arrowY + originalResult[7], // scaleX + originalResult[8], // scaleY + originalResult[9], // alignInfo + mockOnAlign, // onAlign - our mock function + ]; + }); + + // Test component with two controlled triggers + const TestComponent = () => { + const [trigger1Open, setTrigger1Open] = React.useState(true); + const [trigger2Open, setTrigger2Open] = React.useState(false); + + return ( +
+ + + Trigger 1 Popup
} + unique + > +
Trigger 1
+ + Trigger 2 Popup} + unique + > +
Trigger 2
+
+ + + ); + }; + + const { container } = render(); + + // Wait for initial render + await awaitFakeTimer(); + + // Clear any initial calls + mockOnAlign.mockClear(); + + // Switch triggers - this should change the target and call onAlign + fireEvent.click(container.querySelector('.switch-trigger-btn')); + await awaitFakeTimer(); + + // Verify onAlign was called due to target change + expect(mockOnAlign).toHaveBeenCalled(); + }); });