From 91bf3e9b7e862121d8279dd4c7492eebed83427a Mon Sep 17 00:00:00 2001 From: Victoria Zhizhonkova Date: Thu, 7 Nov 2024 17:52:44 +0700 Subject: [PATCH] fix(Tappable): force activated/hovered state (#7906) --- .../src/components/Clickable/useState.tsx | 57 ++++++++++--------- .../src/components/Tappable/Tappable.test.tsx | 23 +++++--- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/packages/vkui/src/components/Clickable/useState.tsx b/packages/vkui/src/components/Clickable/useState.tsx index d230ec53ea..e37d26854f 100644 --- a/packages/vkui/src/components/Clickable/useState.tsx +++ b/packages/vkui/src/components/Clickable/useState.tsx @@ -93,12 +93,13 @@ function useHover({ hovered, hasHover = true, lockState, setParentStateLock }: U (isHover: boolean) => { setHoveredStateLocal(isHover); - const isHovered = calculateStateValue({ - hasState: hasHover, - isLocked: lockState, - stateValueControlled: Boolean(hovered), - stateValueLocal: isHover, - }); + const isHovered = + hovered ?? + calculateStateValue({ + hasState: hasHover, + isLocked: lockState, + stateValueLocal: isHover, + }); // проверка сделана чтобы реже вызывать обновление состояния // контекста родителя @@ -122,12 +123,13 @@ function useHover({ hovered, hasHover = true, lockState, setParentStateLock }: U handleHover(false); }; - const isHovered = calculateStateValue({ - hasState: hasHover, - isLocked: lockState, - stateValueControlled: Boolean(hovered), - stateValueLocal: hoveredStateLocal, - }); + const isHovered = + hovered ?? + calculateStateValue({ + hasState: hasHover, + isLocked: lockState, + stateValueLocal: hoveredStateLocal, + }); return { isHovered, @@ -194,12 +196,13 @@ function useActive({ setActivated(false, activeEffectDelay); }; - const isActivated = calculateStateValue({ - hasState: hasActive, - isLocked: lockStateRef.current, - stateValueControlled: Boolean(activated), - stateValueLocal: activatedState, - }); + const isActivated = + activated ?? + calculateStateValue({ + hasState: hasActive, + isLocked: lockStateRef.current, + stateValueLocal: activatedState, + }); return { isActivated, @@ -262,9 +265,12 @@ function useLockRef( export function useState({ hovered, hasHover, + activated, hasActive, + activeEffectDelay, unlockParentHover, - ...restProps + hoverClassName, + activeClassName, }: StateProps): { stateClassName: string; setLockHoverBubblingImmediate: (...args: any[]) => void; @@ -286,15 +292,14 @@ export function useState({ }); const { isActivated, ...activeEvent } = useActive({ - ...restProps, + activated, + hasActive, + activeEffectDelay, lockStateRef: lockActiveStateRef, setParentStateLock: setParentStateLockActiveBubbling, }); - const stateClassName = classNames( - isHovered && restProps.hoverClassName, - isActivated && restProps.activeClassName, - ); + const stateClassName = classNames(isHovered && hoverClassName, isActivated && activeClassName); const handlers = mergeCalls(hoverEvent, activeEvent); return { @@ -309,13 +314,11 @@ export function useState({ function calculateStateValue({ hasState, isLocked, - stateValueControlled, stateValueLocal, }: { hasState: boolean; isLocked: boolean; - stateValueControlled: boolean; stateValueLocal: boolean; }): boolean { - return hasState && !isLocked && (stateValueControlled || stateValueLocal); + return hasState && !isLocked && stateValueLocal; } diff --git a/packages/vkui/src/components/Tappable/Tappable.test.tsx b/packages/vkui/src/components/Tappable/Tappable.test.tsx index eb659e85ff..28fd5bc52e 100644 --- a/packages/vkui/src/components/Tappable/Tappable.test.tsx +++ b/packages/vkui/src/components/Tappable/Tappable.test.tsx @@ -210,11 +210,12 @@ describe(Tappable, () => { it('activates during longtap', async () => { render(); fireEvent.pointerDown(tappable()); - expect(tappable()).not.toHaveClass(styles['Tappable--activated-background']); - await waitFor(() => expect(tappable()).toHaveClass(styles['Tappable--activated-background'])); + act(jest.runOnlyPendingTimers); + expect(tappable()).toHaveClass(styles['Tappable--activated-background']); fireEvent.pointerUp(tappable()); - expect(tappable()).toHaveClass(styles['Tappable--activated-background']); + act(jest.runOnlyPendingTimers); + expect(tappable()).not.toHaveClass(styles['Tappable--activated-background']); }); it('does not activate on child Tappable click', async () => { @@ -264,12 +265,16 @@ describe(Tappable, () => { expect(tappable()).not.toHaveClass(styles['Tappable--activated-background']); }); - it('on hasActive=false', () => { - const h = render(); - fireEvent.mouseDown(tappable()); - act(jest.runAllTimers); - h.rerender(); - expect(tappable()).not.toHaveClass(styles['Tappable--activated-background']); + it('on hasActive=false', async () => { + render(); + await userEvent.click(tappable()); + let errored = false; + await waitFor(() => + expect(tappable()).toHaveClass(styles['Tappable--activated-background']), + ).catch(() => { + errored = true; + }); + expect(errored).toBeTruthy(); }); it('on child hover', async () => {