From 096aad2be19f5714ea1463aabbde5a7936bf36e4 Mon Sep 17 00:00:00 2001 From: Dylan Kilgore Date: Fri, 20 Oct 2023 15:47:49 -0700 Subject: [PATCH] feat: fadein: add fadein component --- src/components/FadeIn/FadeIn.stories.tsx | 43 ++++++++++++++ src/components/FadeIn/FadeIn.test.tsx | 73 ++++++++++++++++++++++++ src/components/FadeIn/FadeIn.tsx | 38 ++++++++++++ src/components/FadeIn/FadeIn.types.ts | 23 ++++++++ src/components/FadeIn/index.ts | 2 + src/octuple.ts | 3 + 6 files changed, 182 insertions(+) create mode 100644 src/components/FadeIn/FadeIn.stories.tsx create mode 100644 src/components/FadeIn/FadeIn.test.tsx create mode 100644 src/components/FadeIn/FadeIn.tsx create mode 100644 src/components/FadeIn/FadeIn.types.ts create mode 100644 src/components/FadeIn/index.ts diff --git a/src/components/FadeIn/FadeIn.stories.tsx b/src/components/FadeIn/FadeIn.stories.tsx new file mode 100644 index 000000000..04ac7a215 --- /dev/null +++ b/src/components/FadeIn/FadeIn.stories.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { Stories } from '@storybook/addon-docs'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { FadeIn } from './'; + +export default { + title: 'FadeIn', + parameters: { + docs: { + page: (): JSX.Element => ( +
+
+
+

FadeIn

+

A FadeIn allows to render content with a fade in animation.

+
+
+ +
+
+
+ ), + }, + }, +} as ComponentMeta; + +const FadeIn_Story: ComponentStory = (args) => { + return ( + <> + + + ); +}; + +export const Default = FadeIn_Story.bind({}); + +Default.args = { + children: <>Hello, I was faded into view., + classNames: 'my-fadein-classname', + delay: 0, + disabled: false, + duration: 300, +}; diff --git a/src/components/FadeIn/FadeIn.test.tsx b/src/components/FadeIn/FadeIn.test.tsx new file mode 100644 index 000000000..3d9fadf31 --- /dev/null +++ b/src/components/FadeIn/FadeIn.test.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import Enzyme from 'enzyme'; +import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; +import MatchMediaMock from 'jest-matchmedia-mock'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import { FadeIn } from './FadeIn'; +import { sleep } from '../../tests/Utilities'; + +Enzyme.configure({ adapter: new Adapter() }); + +let matchMedia: any; + +describe('FadeIn', () => { + beforeAll(() => { + matchMedia = new MatchMediaMock(); + }); + + afterEach(() => { + matchMedia.clear(); + }); + + test('Should render children', () => { + const { getByText } = render(Hello, World!); + expect(getByText('Hello, World!')).toBeInTheDocument(); + }); + + test('Should apply the given classNames', () => { + const { container } = render( + Hello, World! + ); + const fadeInElement = container.querySelector('.custom-class'); + expect(fadeInElement).toBeInTheDocument(); + }); + + test('Should apply the animation styles', async () => { + const { getByTestId } = render( + Hello, World! + ); + const fadeInElement = getByTestId('test-fadein'); + + expect(fadeInElement).toHaveStyle('opacity: 0'); + + await sleep(400); + expect(fadeInElement).toHaveStyle('opacity: 1'); + }); + + test('Should not animate if disabled prop is set to true', async () => { + const { getByTestId } = render( + + Hello, World! + + ); + const fadeInElement = getByTestId('test-fadein'); + + expect(fadeInElement).toHaveStyle('opacity: 0'); + + await sleep(100); + expect(fadeInElement).toHaveStyle('opacity: 1'); + }); + + test('Should apply the given duration for animation', async () => { + const { getByTestId } = render( + + Hello, World! + + ); + const fadeInElement = getByTestId('test-fadein'); + + await sleep(1100); + expect(fadeInElement).toHaveStyle('opacity: 1'); + }); +}); diff --git a/src/components/FadeIn/FadeIn.tsx b/src/components/FadeIn/FadeIn.tsx new file mode 100644 index 000000000..cc500b327 --- /dev/null +++ b/src/components/FadeIn/FadeIn.tsx @@ -0,0 +1,38 @@ +import React, { FC, Ref } from 'react'; +import { FadeInProps } from './FadeIn.types'; +import { animated, useSpring, UseSpringProps } from '@react-spring/web'; + +export const FadeIn: FC = React.forwardRef( + (props: FadeInProps, ref: Ref) => { + const { + children, + classNames, + delay = 0, + disabled = false, + duration = 300, + 'data-testid': dataTestId, + ...rest + } = props; + const styles: UseSpringProps<{ opacity: number }> = useSpring({ + to: { opacity: 1 }, + from: { opacity: 0 }, + config: { + duration, + }, + delay, + immediate: disabled, + }); + + return ( + + {children} + + ); + } +); diff --git a/src/components/FadeIn/FadeIn.types.ts b/src/components/FadeIn/FadeIn.types.ts new file mode 100644 index 000000000..46d63b939 --- /dev/null +++ b/src/components/FadeIn/FadeIn.types.ts @@ -0,0 +1,23 @@ +import { ReactNode } from 'react'; +import { OcBaseProps } from '../OcBase'; + +export interface FadeInProps extends OcBaseProps { + /** + * The FadeIn child renderer. + */ + children: ReactNode; + /** + * The FadeIn delay amount. + */ + delay?: number; + /** + * The FadeIn animation duration. + * @default 300 + */ + duration?: number; + /** + * Whether the FadeIn style is disabled. + * @default false + */ + disabled?: boolean; +} diff --git a/src/components/FadeIn/index.ts b/src/components/FadeIn/index.ts new file mode 100644 index 000000000..a3e3d87cf --- /dev/null +++ b/src/components/FadeIn/index.ts @@ -0,0 +1,2 @@ +export * from './FadeIn'; +export * from './FadeIn.types'; diff --git a/src/octuple.ts b/src/octuple.ts index 7fe7c9984..cd9367d00 100644 --- a/src/octuple.ts +++ b/src/octuple.ts @@ -72,6 +72,8 @@ import { Dropdown } from './components/Dropdown'; import { Empty, EmptyMode } from './components/Empty'; +import { FadeIn } from './components/FadeIn'; + import Form, { FormInstance } from './components/Form'; import Grid, { Col, Row } from './components/Grid'; @@ -297,6 +299,7 @@ export { Empty, EmptyMode, ExpandableConfig, + FadeIn, FilterConfirmProps, FilterValue, Form,