mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
fix(ui): update SmartInput animation (#3216)
This commit is contained in:
parent
d240d26031
commit
ab65d895b5
4 changed files with 38 additions and 15 deletions
|
@ -288,3 +288,17 @@ export const mockSignInMethodSettingsTestCases: Array<SignIn['methods']> = [
|
|||
},
|
||||
],
|
||||
];
|
||||
|
||||
export const getBoundingClientRectMock = (mock: Partial<DOMRect>) =>
|
||||
jest.fn(() => ({
|
||||
width: 0,
|
||||
height: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
...mock,
|
||||
toJSON: jest.fn(),
|
||||
}));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { onResize, useIsomorphicLayoutEffect } from '@react-spring/shared';
|
||||
import { useSpring, animated, config } from '@react-spring/web';
|
||||
import type { Nullable } from '@silverhand/essentials';
|
||||
import { cloneElement, useCallback, useRef } from 'react';
|
||||
import { cloneElement, useCallback, useRef, useState } from 'react';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
|
@ -11,6 +11,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const AnimatedPrefix = ({ children, isVisible }: Props) => {
|
||||
const [domReady, setDomReady] = useState(false);
|
||||
const elementRef = useRef<Nullable<HTMLElement>>(null);
|
||||
|
||||
// Get target width for the children
|
||||
|
@ -21,11 +22,14 @@ const AnimatedPrefix = ({ children, isVisible }: Props) => {
|
|||
|
||||
const [animation, api] = useSpring(
|
||||
() => ({ width: getTargetWidth(), config: { ...config.default, clamp: true } }),
|
||||
[getTargetWidth]
|
||||
[getTargetWidth, domReady]
|
||||
);
|
||||
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const { current } = elementRef;
|
||||
|
||||
setDomReady(true);
|
||||
|
||||
const cleanup =
|
||||
current &&
|
||||
onResize(
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Globals } from '@react-spring/web';
|
|||
import { assert } from '@silverhand/essentials';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { getBoundingClientRectMock } from '@/__mocks__/logto';
|
||||
import { getDefaultCountryCallingCode } from '@/utils/country-code';
|
||||
|
||||
import type { IdentifierInputType } from '.';
|
||||
|
@ -15,6 +16,7 @@ jest.mock('i18next', () => ({
|
|||
|
||||
describe('SmartInputField Component', () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
const defaultCountryCallingCode = getDefaultCountryCallingCode();
|
||||
|
||||
const renderInputField = (props: {
|
||||
|
@ -27,6 +29,11 @@ describe('SmartInputField Component', () => {
|
|||
Globals.assign({
|
||||
skipAnimation: true,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||
window.HTMLDivElement.prototype.getBoundingClientRect = getBoundingClientRectMock({
|
||||
width: 100,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -65,10 +72,7 @@ describe('SmartInputField Component', () => {
|
|||
const countryCode = queryAllByText(`+${defaultCountryCallingCode}`);
|
||||
expect(countryCode).toHaveLength(2);
|
||||
|
||||
// Country code select should have a >0 width.
|
||||
// The React Spring acquires the child element's width ahead of elementRef is properly set.
|
||||
// So the value returns null. Assert style is null to represent the width is >0.
|
||||
expect(queryByTestId('prefix')?.getAttribute('style')).toBe(null);
|
||||
expect(queryByTestId('prefix')?.style.width).toBe('100px');
|
||||
|
||||
const selector = container.querySelector('select');
|
||||
assert(selector, new Error('selector should not be null'));
|
||||
|
|
|
@ -5,7 +5,7 @@ import { MemoryRouter, useLocation } from 'react-router-dom';
|
|||
|
||||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
|
||||
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
|
||||
import { mockSignInExperienceSettings } from '@/__mocks__/logto';
|
||||
import { mockSignInExperienceSettings, getBoundingClientRectMock } from '@/__mocks__/logto';
|
||||
import type { SignInExperienceResponse } from '@/types';
|
||||
|
||||
import ForgotPassword from '.';
|
||||
|
@ -43,6 +43,11 @@ describe('ForgotPassword', () => {
|
|||
Globals.assign({
|
||||
skipAnimation: true,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||
window.HTMLDivElement.prototype.getBoundingClientRect = getBoundingClientRectMock({
|
||||
width: 100,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -79,6 +84,7 @@ describe('ForgotPassword', () => {
|
|||
const { queryByText, queryAllByText, container, queryByTestId } = renderPage(settings);
|
||||
const inputField = container.querySelector('input[name="identifier"]');
|
||||
const countryCodeSelectorPrefix = queryByTestId('prefix');
|
||||
|
||||
assert(inputField, new Error('input field not found'));
|
||||
|
||||
expect(queryByText('description.reset_password')).not.toBeNull();
|
||||
|
@ -88,12 +94,7 @@ describe('ForgotPassword', () => {
|
|||
|
||||
if (state.identifier === SignInIdentifier.Phone && settings.phone) {
|
||||
expect(inputField.getAttribute('value')).toBe(phone);
|
||||
|
||||
// Country code select should have a >0 width.
|
||||
// The React Spring acquires the child element's width ahead of elementRef is properly set.
|
||||
// So the value returns null. Assert style is null to represent the width is >0.
|
||||
expect(countryCodeSelectorPrefix?.getAttribute('style')).toBeNull();
|
||||
|
||||
expect(countryCodeSelectorPrefix?.style.width).toBe('100px');
|
||||
expect(queryAllByText(`+${countryCode}`)).toHaveLength(2);
|
||||
} else if (state.identifier === SignInIdentifier.Phone) {
|
||||
// Phone Number not enabled
|
||||
|
@ -107,7 +108,7 @@ describe('ForgotPassword', () => {
|
|||
} else if (state.identifier === SignInIdentifier.Email) {
|
||||
// Only PhoneNumber is enabled
|
||||
expect(inputField.getAttribute('value')).toBe('');
|
||||
expect(countryCodeSelectorPrefix?.getAttribute('style')).toBeNull();
|
||||
expect(countryCodeSelectorPrefix?.style.width).toBe('100px');
|
||||
}
|
||||
|
||||
if (state.identifier === SignInIdentifier.Username && settings.email) {
|
||||
|
@ -116,7 +117,7 @@ describe('ForgotPassword', () => {
|
|||
} else if (state.identifier === SignInIdentifier.Username) {
|
||||
// Only PhoneNumber is enabled
|
||||
expect(inputField.getAttribute('value')).toBe('');
|
||||
expect(countryCodeSelectorPrefix?.getAttribute('style')).toBeNull();
|
||||
expect(countryCodeSelectorPrefix?.style.width).toBe('100px');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue