From d818df0326536f9d94b5297babb2919acad607cd Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 2 May 2023 11:32:29 -0400 Subject: [PATCH 01/21] init --- packages/gamut/src/Markdown/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index fe9bbecaa9..1724a6b0bf 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -1,3 +1,4 @@ +import { PausableImage } from '@codecademy/gamut-labs'; import cx from 'classnames'; import HtmlToReact from 'html-to-react'; import marked from 'marked'; @@ -122,6 +123,9 @@ export class Markdown extends PureComponent { createInputOverride('checkbox', { component: MarkdownCheckbox, }), + createInputOverride('img', { + component: PausableImage, + }), ...overrides, ...standardOverrides, ].filter(Boolean); From d3650be066a41d65ed14444e7b6208848a4b3c61 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 3 May 2023 10:08:44 -0400 Subject: [PATCH 02/21] override processnode --- packages/gamut/src/Markdown/index.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index 1724a6b0bf..68924840a9 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -41,6 +41,7 @@ export type SkipDefaultOverridesSettings = { details?: boolean; iframe?: boolean; table?: boolean; + img?: boolean; }; export type MarkdownProps = { @@ -123,9 +124,18 @@ export class Markdown extends PureComponent { createInputOverride('checkbox', { component: MarkdownCheckbox, }), - createInputOverride('img', { - component: PausableImage, - }), + !skipDefaultOverrides.img && + createTagOverride('img', { + component: PausableImage, + processNode: (node, props) => { + // Note: this processNode override is necessary because wrapping this component + // has children components which will cause react rendering to crash because + // the img tag does not support children. + return ( + + ); + }, + }), ...overrides, ...standardOverrides, ].filter(Boolean); From 30d386d50b43da18b5f492ad04652fb985e7972b Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 9 May 2023 13:32:55 -0400 Subject: [PATCH 03/21] add pausable image to gamut --- .../gamut-labs/src/LandingPage/Feature.tsx | 9 ++- packages/gamut/src/Markdown/index.tsx | 13 +--- .../src/Markdown/libs/overrides/index.tsx | 31 ++++++++ .../BaseImage/__tests__/BaseImage.test.tsx | 31 ++++++++ .../src/PausableImage/BaseImage/index.tsx | 73 +++++++++++++++++++ .../__tests__/PausableImage.test.tsx | 32 ++++++++ packages/gamut/src/PausableImage/index.tsx | 44 +++++++++++ packages/gamut/src/index.tsx | 1 + .../gamut/src/typings/react-freezeframe.d.ts | 1 + .../Molecules/PausableImage.stories.mdx | 46 ++++++++++++ .../Organisms/Markdown/index.stories.mdx | 34 ++++++++- 11 files changed, 302 insertions(+), 13 deletions(-) create mode 100644 packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx create mode 100644 packages/gamut/src/PausableImage/BaseImage/index.tsx create mode 100644 packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx create mode 100644 packages/gamut/src/PausableImage/index.tsx create mode 100644 packages/gamut/src/typings/react-freezeframe.d.ts create mode 100644 packages/styleguide/stories/Molecules/PausableImage.stories.mdx diff --git a/packages/gamut-labs/src/LandingPage/Feature.tsx b/packages/gamut-labs/src/LandingPage/Feature.tsx index 5ac4db6766..bc37e7ab86 100644 --- a/packages/gamut-labs/src/LandingPage/Feature.tsx +++ b/packages/gamut-labs/src/LandingPage/Feature.tsx @@ -1,9 +1,14 @@ -import { Box, Markdown, Text, WithChildrenProp } from '@codecademy/gamut'; +import { + Box, + Markdown, + PausableImage, + Text, + WithChildrenProp, +} from '@codecademy/gamut'; import { mediaQueries } from '@codecademy/gamut-styles'; import styled from '@emotion/styled'; import * as React from 'react'; -import { PausableImage } from '../PausableImage'; import { BaseProps } from './types'; const Image = Box.withComponent('img'); diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index 68924840a9..d018a8a02d 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -1,4 +1,3 @@ -import { PausableImage } from '@codecademy/gamut-labs'; import cx from 'classnames'; import HtmlToReact from 'html-to-react'; import marked from 'marked'; @@ -6,9 +5,11 @@ import { PureComponent } from 'react'; import * as React from 'react'; import sanitizeMarkdown from 'sanitize-markdown'; +import { PausableImage } from '../PausableImage'; import { omitProps } from '../utils/omitProps'; import { createCodeBlockOverride, + createImgOverride, createInputOverride, createTagOverride, ManyOverrideSettings, @@ -125,16 +126,8 @@ export class Markdown extends PureComponent { component: MarkdownCheckbox, }), !skipDefaultOverrides.img && - createTagOverride('img', { + createImgOverride('img', { component: PausableImage, - processNode: (node, props) => { - // Note: this processNode override is necessary because wrapping this component - // has children components which will cause react rendering to crash because - // the img tag does not support children. - return ( - - ); - }, }), ...overrides, ...standardOverrides, diff --git a/packages/gamut/src/Markdown/libs/overrides/index.tsx b/packages/gamut/src/Markdown/libs/overrides/index.tsx index 1c8e9ee8eb..cc14941f41 100644 --- a/packages/gamut/src/Markdown/libs/overrides/index.tsx +++ b/packages/gamut/src/Markdown/libs/overrides/index.tsx @@ -198,3 +198,34 @@ export const standardOverrides = [ processNode: processNodeDefinitions.processDefaultNode, }, ]; + +// img tag override +export const createImgOverride = ( + tagName: string, + Override: OverrideSettings +) => ({ + shouldProcessNode(node: HTMLToReactNode) { + if (!Override) return false; + + if (Override.shouldProcessNode) { + return Override.shouldProcessNode(node); + } + return node.name === tagName.toLowerCase(); + }, + processNode(node: HTMLToReactNode, key: React.Key) { + if (!Override) return null; + + const props = { + ...processAttributes(node.attribs), + key, + }; + + if (Override.processNode) { + return Override.processNode(node, props); + } + + if (!Override.component) return null; + + return ; + }, +}); diff --git a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx new file mode 100644 index 0000000000..ce07b69dba --- /dev/null +++ b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx @@ -0,0 +1,31 @@ +import { setupRtl } from '@codecademy/gamut-tests'; +import userEvent from '@testing-library/user-event'; + +import { BaseImage } from '..'; + +jest.mock('react-freezeframe', () => ({ src }: { src: string }) => ( + +)); + +const renderView = setupRtl(BaseImage, { + alt: '', + src: 'image.gif', +}); + +describe('BaseImage', () => { + it('renders a playing image by default', () => { + const { view } = renderView(); + expect(view.getAllByRole('img')[0]).toHaveAttribute('src', 'image.gif'); + }); + + it('renders a paused image after clicking pause', async () => { + const { view } = renderView(); + + await userEvent.click(view.getByRole('button')); + + expect(view.getAllByRole('img')[0]).toHaveAttribute( + 'src', + 'frozen-image.gif' + ); + }); +}); diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx new file mode 100644 index 0000000000..98d6b4ac1f --- /dev/null +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -0,0 +1,73 @@ +import { PauseIcon, PlayIcon } from '@codecademy/gamut-icons'; +import { css } from '@codecademy/gamut-styles'; +import styled from '@emotion/styled'; +import { useState } from 'react'; +import * as React from 'react'; +import Freezeframe from 'react-freezeframe'; + +import { Box } from '../../Box'; +import { FillButton } from '../../Button'; +import { HiddenText } from '../../HiddenText'; +import { imageStyles, PauseableImageProps } from '..'; + +export interface BaseImageProps extends PauseableImageProps {} + +export const Container = styled(Box)( + css({ + alignItems: 'center', + justifyContent: 'center', + height: '100%', + display: 'flex', + position: 'relative', + width: '100%', + [`> img, + > .react-freezeframe, + > .react-freezeframe img`]: { + maxWidth: '100%', + height: '100%', + }, + '.ff-container': { + height: '100%', + }, + '.ff-container .ff-canvas': { + transition: 'none', + }, + '.ff-loading-icon::before': { + display: 'none', + }, + }) +); + +export const PlayingImage = imageStyles; + +const StyledFreezeframe = styled(Freezeframe)(imageStyles); + +export const BaseImage: React.FC = ({ alt, ...rest }) => { + const [paused, setPaused] = useState(false); + + const [liveText, buttonLabel, Icon, Image] = paused + ? [`${alt}, paused`, 'Play animated image', PlayIcon, StyledFreezeframe] + : [`${alt}, playing`, 'Pause animated image', PauseIcon, PlayingImage]; + + return ( + + {alt} + {/* ensure proper fall back label if an empty string is given as alt */} + {alt ? liveText : buttonLabel} + setPaused(!paused)} + position="absolute" + right={0} + variant="secondary" + zIndex={1} + aria-label={buttonLabel} + > + + + + ); +}; + +export default BaseImage; diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx new file mode 100644 index 0000000000..5ef8be49b2 --- /dev/null +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -0,0 +1,32 @@ +import { setupRtl } from '@codecademy/gamut-tests'; +import { waitFor } from '@testing-library/react'; + +import { PausableImage } from '..'; + +const renderView = setupRtl(PausableImage); + +const createImg = (url: string) => ({ + alt: '', + src: url, +}); + +describe('PausableImage', () => { + it('renders a pausable image when the URL ends with .gif', async () => { + const { view } = await renderView({ + ...createImg('image.gif'), + }); + + // wait to find static image while loading pause ui + view.getByRole('img'); + // wait to find pause button + await waitFor(() => view.findByText('Pause animated image')); + }); + + it('renders a static image when the URL does not end with .gif', () => { + const { view } = renderView({ + ...createImg('image.svg'), + }); + + expect(view.getByRole('img')).toHaveAttribute('src', 'image.svg'); + }); +}); diff --git a/packages/gamut/src/PausableImage/index.tsx b/packages/gamut/src/PausableImage/index.tsx new file mode 100644 index 0000000000..ba812c0a65 --- /dev/null +++ b/packages/gamut/src/PausableImage/index.tsx @@ -0,0 +1,44 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import * as React from 'react'; + +const BaseImage = React.lazy(() => import('./BaseImage')); + +export interface PauseableImageProps { + src: string; + alt: string; +} +export const imageStyles = styled.img( + css({ + height: 'auto', + maxHeight: '100%', + maxWidth: '100%', + '&[src$=".svg"]': { + width: '100%', + }, + }) +); + +const StaticImage = imageStyles; + +export const PausableImage: React.FC = (props) => { + const staticImage = ; + + // Avoid rendering React.Suspense on the server until it's fully supported by React & our applications + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + return ( + <> + {isMounted && props.src?.endsWith('.gif') ? ( + + + + ) : ( + staticImage + )} + + ); +}; diff --git a/packages/gamut/src/index.tsx b/packages/gamut/src/index.tsx index 9598d0311e..fd0aa1da2a 100644 --- a/packages/gamut/src/index.tsx +++ b/packages/gamut/src/index.tsx @@ -40,6 +40,7 @@ export * from './NotificationList/NotificationItem'; export * from './NotificationList/typings'; export * from './Overlay'; export * from './Pagination'; +export * from './PausableImage'; export * from './Popover'; export * from './PopoverContainer'; export * from './ProgressBar'; diff --git a/packages/gamut/src/typings/react-freezeframe.d.ts b/packages/gamut/src/typings/react-freezeframe.d.ts new file mode 100644 index 0000000000..83e1c91c0c --- /dev/null +++ b/packages/gamut/src/typings/react-freezeframe.d.ts @@ -0,0 +1 @@ +declare module 'react-freezeframe'; diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx new file mode 100644 index 0000000000..a53781782f --- /dev/null +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -0,0 +1,46 @@ +import { PausableImage } from '@codecademy/gamut'; +import title from '@codecademy/macros/lib/title.macro'; +import { PropsTable } from '@codecademy/storybook-addon-variance'; +import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; + +import { LinkTo } from '~styleguide/blocks'; + + + + + + {(args) => } + + + + + +## Usage + +```tsx +import { PausableImage } from '@codecademy/gamut'; + +; +``` + +## Color Modes + +PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. + +- Use the colormode changer of the top of the page to see the change diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index fa3f3147db..425dae8220 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -1,4 +1,4 @@ -import { Markdown, Text } from '@codecademy/gamut/src'; +import { Column, LayoutGrid, Markdown, Text } from '@codecademy/gamut/src'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -66,6 +66,38 @@ A common override may be to change the font size of a Heading. +Img tags are overwitten by the PausableImage component because of the accessibility benefits it provides. +When provided with a Gif it allow the user to pause the gif. + + + ', + }} + > + + + ' + } + /> + + + ' + } + /> + + + + + If you need to override a link, iframe, or table, you also need to provide the `skipDefaultOverides` prop. export const overrides = { From e8f976c87218cecf4700ae921d516dfe2b9e9cc0 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 9 May 2023 15:43:46 -0400 Subject: [PATCH 04/21] fix test --- .../src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx index ce07b69dba..336facae31 100644 --- a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx @@ -18,10 +18,10 @@ describe('BaseImage', () => { expect(view.getAllByRole('img')[0]).toHaveAttribute('src', 'image.gif'); }); - it('renders a paused image after clicking pause', async () => { + it('renders a paused image after clicking pause', () => { const { view } = renderView(); - await userEvent.click(view.getByRole('button')); + userEvent.click(view.getByRole('button')); expect(view.getAllByRole('img')[0]).toHaveAttribute( 'src', From ed4842a69998f1273b57b0ec4f8a4954c67bac0e Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 10 May 2023 11:04:27 -0400 Subject: [PATCH 05/21] prevent default of the container --- .../src/Markdown/__tests__/Markdown.test.tsx | 26 ++++++++++++++++++- .../src/PausableImage/BaseImage/index.tsx | 8 +++++- .../__tests__/PausableImage.test.tsx | 2 +- .../Molecules/PausableImage.stories.mdx | 23 +++++++++++++++- .../Organisms/Markdown/index.stories.mdx | 2 +- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx index aefc4b3018..c3a62d251b 100644 --- a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx +++ b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/no-distracting-elements */ import { setupRtl } from '@codecademy/gamut-tests'; -import { act, screen } from '@testing-library/react'; +import { act, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import * as React from 'react'; @@ -205,6 +205,30 @@ var test = true; screen.getByRole('img'); }); + it('renders a pausable image when the URL ends with .gif', async () => { + renderView({ + text: ``, + }); + + // wait to find static image while loading pause ui + screen.getByRole('img'); + // wait to find pause button + await waitFor(() => screen.findByText('Pause animated image')); + }); + + it(`doesn't renders a pausable image when the URL ends with .gif`, async () => { + renderView({ + text: ``, + }); + + // wait to find static image while loading pause ui + screen.getByRole('img'); + // wait to find pause button + await waitFor(() => + expect(screen.queryByText('Pause animated image')).toBeNull() + ); + }); + it('Allows passing in class names', () => { renderView({ text: `
# Cool
`, diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx index 98d6b4ac1f..9fcef2c408 100644 --- a/packages/gamut/src/PausableImage/BaseImage/index.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -57,7 +57,13 @@ export const BaseImage: React.FC = ({ alt, ...rest }) => { setPaused(!paused)} + onClick={(e) => { + setPaused(!paused); + // preventing the deafualt behavior of the image + // container from preventing the button image from + // being paused e.g. if the image is in a link + e.preventDefault(); + }} position="absolute" right={0} variant="secondary" diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx index 5ef8be49b2..cb03886f55 100644 --- a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -12,7 +12,7 @@ const createImg = (url: string) => ({ describe('PausableImage', () => { it('renders a pausable image when the URL ends with .gif', async () => { - const { view } = await renderView({ + const { view } = renderView({ ...createImg('image.gif'), }); diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index a53781782f..85dfbd5de7 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { PausableImage } from '@codecademy/gamut'; +import { Anchor, PausableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -39,6 +39,27 @@ import { PausableImage } from '@codecademy/gamut'; ; ``` +## Interactive Container + +If the image is wrapped in an interactive container, we prevent the default of the container whe clicking the toggle button. This is useful for when the image is wrapped in an anchor tag. + + + + {(args) => ( + + + + )} + + + ## Color Modes PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index 425dae8220..31924ee484 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -90,7 +90,7 @@ When provided with a Gif it allow the user to pause the gif. ' + ' demonstration of learning environment' } /> From 97950fced1bb89425e64cab3906d1336f0f03578 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 10 May 2023 14:30:26 -0400 Subject: [PATCH 06/21] update snapshot --- packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index 9b4cfedf6e..6316b93c45 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -55,6 +55,7 @@ Array [ "HiddenText", "IconButton", "iFrameWrapper", + "imageStyles", "Input", "InputStepper", "isClickableCrumb", @@ -78,6 +79,7 @@ Array [ "omitProps", "Overlay", "Pagination", + "PausableImage", "Popover", "PopoverContainer", "ProgressBar", From 9f9a9faaba092ef9dcadf43e38b15def80c937e8 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Thu, 11 May 2023 11:32:15 -0400 Subject: [PATCH 07/21] update story --- packages/gamut-labs/src/LandingPage/Feature.tsx | 9 ++------- packages/gamut/src/Markdown/libs/overrides/index.tsx | 2 +- .../stories/Organisms/Markdown/index.stories.mdx | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/gamut-labs/src/LandingPage/Feature.tsx b/packages/gamut-labs/src/LandingPage/Feature.tsx index bc37e7ab86..5ac4db6766 100644 --- a/packages/gamut-labs/src/LandingPage/Feature.tsx +++ b/packages/gamut-labs/src/LandingPage/Feature.tsx @@ -1,14 +1,9 @@ -import { - Box, - Markdown, - PausableImage, - Text, - WithChildrenProp, -} from '@codecademy/gamut'; +import { Box, Markdown, Text, WithChildrenProp } from '@codecademy/gamut'; import { mediaQueries } from '@codecademy/gamut-styles'; import styled from '@emotion/styled'; import * as React from 'react'; +import { PausableImage } from '../PausableImage'; import { BaseProps } from './types'; const Image = Box.withComponent('img'); diff --git a/packages/gamut/src/Markdown/libs/overrides/index.tsx b/packages/gamut/src/Markdown/libs/overrides/index.tsx index cc14941f41..c2434dfc5e 100644 --- a/packages/gamut/src/Markdown/libs/overrides/index.tsx +++ b/packages/gamut/src/Markdown/libs/overrides/index.tsx @@ -199,7 +199,7 @@ export const standardOverrides = [ }, ]; -// img tag override +// Allows for img tag override, which is separate because it doesn't have children export const createImgOverride = ( tagName: string, Override: OverrideSettings diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index 31924ee484..d565102d5f 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -90,7 +90,7 @@ When provided with a Gif it allow the user to pause the gif. demonstration of learning environment' + 'demonstration of learning environment' } /> From 137b6869fd8037baea4a21d3705ebf46da30303a Mon Sep 17 00:00:00 2001 From: vonbarown Date: Fri, 12 May 2023 09:38:59 -0400 Subject: [PATCH 08/21] remove double announcement --- .../src/Markdown/__tests__/Markdown.test.tsx | 2 +- .../src/PausableImage/BaseImage/index.tsx | 30 +++++++++++-------- .../Molecules/PausableImage.stories.mdx | 23 +------------- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx index c3a62d251b..94743eab43 100644 --- a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx +++ b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx @@ -216,7 +216,7 @@ var test = true; await waitFor(() => screen.findByText('Pause animated image')); }); - it(`doesn't renders a pausable image when the URL ends with .gif`, async () => { + it(`doesn't render a pausable image when the URL doesn't end with .gif`, async () => { renderView({ text: ``, }); diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx index 9fcef2c408..f74751d305 100644 --- a/packages/gamut/src/PausableImage/BaseImage/index.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -7,7 +7,6 @@ import Freezeframe from 'react-freezeframe'; import { Box } from '../../Box'; import { FillButton } from '../../Button'; -import { HiddenText } from '../../HiddenText'; import { imageStyles, PauseableImageProps } from '..'; export interface BaseImageProps extends PauseableImageProps {} @@ -45,25 +44,30 @@ const StyledFreezeframe = styled(Freezeframe)(imageStyles); export const BaseImage: React.FC = ({ alt, ...rest }) => { const [paused, setPaused] = useState(false); - const [liveText, buttonLabel, Icon, Image] = paused - ? [`${alt}, paused`, 'Play animated image', PlayIcon, StyledFreezeframe] - : [`${alt}, playing`, 'Pause animated image', PauseIcon, PlayingImage]; + const [liveText, buttonLabel, altFallBack, Icon, Image] = paused + ? [ + `${alt}, paused`, + 'Play animated image', + 'Playing animated image', + PlayIcon, + StyledFreezeframe, + ] + : [ + `${alt}, playing`, + 'Pause animated image', + 'Paused animated image', + PauseIcon, + PlayingImage, + ]; return ( - {alt} {/* ensure proper fall back label if an empty string is given as alt */} - {alt ? liveText : buttonLabel} + {alt { - setPaused(!paused); - // preventing the deafualt behavior of the image - // container from preventing the button image from - // being paused e.g. if the image is in a link - e.preventDefault(); - }} + onClick={() => setPaused(!paused)} position="absolute" right={0} variant="secondary" diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index 85dfbd5de7..a53781782f 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { Anchor, PausableImage } from '@codecademy/gamut'; +import { PausableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -39,27 +39,6 @@ import { PausableImage } from '@codecademy/gamut'; ; ``` -## Interactive Container - -If the image is wrapped in an interactive container, we prevent the default of the container whe clicking the toggle button. This is useful for when the image is wrapped in an anchor tag. - - - - {(args) => ( - - - - )} - - - ## Color Modes PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. From 027a591e632b6bca9008e28ff6c1bfabf14719be Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 2 May 2023 11:32:29 -0400 Subject: [PATCH 09/21] init --- packages/gamut/src/Markdown/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index 777745f67b..4bc80be1b4 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -1,3 +1,4 @@ +import { PausableImage } from '@codecademy/gamut-labs'; import cx from 'classnames'; import HtmlToReact from 'html-to-react'; import { marked } from 'marked'; @@ -123,6 +124,10 @@ export class Markdown extends PureComponent { createInputOverride('checkbox', { component: MarkdownCheckbox, }), + createInputOverride('img', { + component: PausableImage, + }), + ...overrides, ...standardOverrides, ].filter(Boolean); From 3a6ca7853458b8046d9d449104bd871ac3f242d4 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 3 May 2023 10:08:44 -0400 Subject: [PATCH 10/21] override processnode --- packages/gamut/src/Markdown/index.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index 4bc80be1b4..9b6c105446 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -41,6 +41,7 @@ export type SkipDefaultOverridesSettings = { details?: boolean; iframe?: boolean; table?: boolean; + img?: boolean; }; export type MarkdownProps = { @@ -124,9 +125,18 @@ export class Markdown extends PureComponent { createInputOverride('checkbox', { component: MarkdownCheckbox, }), - createInputOverride('img', { - component: PausableImage, - }), + !skipDefaultOverrides.img && + createTagOverride('img', { + component: PausableImage, + processNode: (node, props) => { + // Note: this processNode override is necessary because wrapping this component + // has children components which will cause react rendering to crash because + // the img tag does not support children. + return ( + + ); + }, + }), ...overrides, ...standardOverrides, ].filter(Boolean); From b9dd97e3f57bb0a191e2f0cd0fc27d2b6fac2ed5 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 9 May 2023 13:32:55 -0400 Subject: [PATCH 11/21] add pausable image to gamut --- packages/gamut/src/Markdown/index.tsx | 13 +--- .../src/Markdown/libs/overrides/index.tsx | 31 ++++++++ .../BaseImage/__tests__/BaseImage.test.tsx | 31 ++++++++ .../src/PausableImage/BaseImage/index.tsx | 73 +++++++++++++++++++ .../__tests__/PausableImage.test.tsx | 32 ++++++++ packages/gamut/src/PausableImage/index.tsx | 44 +++++++++++ packages/gamut/src/index.tsx | 1 + .../gamut/src/typings/react-freezeframe.d.ts | 1 + .../Molecules/PausableImage.stories.mdx | 46 ++++++++++++ .../Organisms/Markdown/index.stories.mdx | 34 ++++++++- 10 files changed, 295 insertions(+), 11 deletions(-) create mode 100644 packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx create mode 100644 packages/gamut/src/PausableImage/BaseImage/index.tsx create mode 100644 packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx create mode 100644 packages/gamut/src/PausableImage/index.tsx create mode 100644 packages/gamut/src/typings/react-freezeframe.d.ts create mode 100644 packages/styleguide/stories/Molecules/PausableImage.stories.mdx diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index 9b6c105446..bd9cbae8cf 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -1,4 +1,3 @@ -import { PausableImage } from '@codecademy/gamut-labs'; import cx from 'classnames'; import HtmlToReact from 'html-to-react'; import { marked } from 'marked'; @@ -6,9 +5,11 @@ import { PureComponent } from 'react'; import * as React from 'react'; import sanitizeMarkdown from 'sanitize-markdown'; +import { PausableImage } from '../PausableImage'; import { omitProps } from '../utils/omitProps'; import { createCodeBlockOverride, + createImgOverride, createInputOverride, createTagOverride, MarkdownOverrideSettings, @@ -126,16 +127,8 @@ export class Markdown extends PureComponent { component: MarkdownCheckbox, }), !skipDefaultOverrides.img && - createTagOverride('img', { + createImgOverride('img', { component: PausableImage, - processNode: (node, props) => { - // Note: this processNode override is necessary because wrapping this component - // has children components which will cause react rendering to crash because - // the img tag does not support children. - return ( - - ); - }, }), ...overrides, ...standardOverrides, diff --git a/packages/gamut/src/Markdown/libs/overrides/index.tsx b/packages/gamut/src/Markdown/libs/overrides/index.tsx index de4f124d0f..5dfc427e82 100644 --- a/packages/gamut/src/Markdown/libs/overrides/index.tsx +++ b/packages/gamut/src/Markdown/libs/overrides/index.tsx @@ -201,3 +201,34 @@ export const standardOverrides = [ processNode: processNodeDefinitions.processDefaultNode, }, ]; + +// img tag override +export const createImgOverride = ( + tagName: string, + Override: OverrideSettings +) => ({ + shouldProcessNode(node: HTMLToReactNode) { + if (!Override) return false; + + if (Override.shouldProcessNode) { + return Override.shouldProcessNode(node); + } + return node.name === tagName.toLowerCase(); + }, + processNode(node: HTMLToReactNode, key: React.Key) { + if (!Override) return null; + + const props = { + ...processAttributes(node.attribs), + key, + }; + + if (Override.processNode) { + return Override.processNode(node, props); + } + + if (!Override.component) return null; + + return ; + }, +}); diff --git a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx new file mode 100644 index 0000000000..ce07b69dba --- /dev/null +++ b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx @@ -0,0 +1,31 @@ +import { setupRtl } from '@codecademy/gamut-tests'; +import userEvent from '@testing-library/user-event'; + +import { BaseImage } from '..'; + +jest.mock('react-freezeframe', () => ({ src }: { src: string }) => ( + +)); + +const renderView = setupRtl(BaseImage, { + alt: '', + src: 'image.gif', +}); + +describe('BaseImage', () => { + it('renders a playing image by default', () => { + const { view } = renderView(); + expect(view.getAllByRole('img')[0]).toHaveAttribute('src', 'image.gif'); + }); + + it('renders a paused image after clicking pause', async () => { + const { view } = renderView(); + + await userEvent.click(view.getByRole('button')); + + expect(view.getAllByRole('img')[0]).toHaveAttribute( + 'src', + 'frozen-image.gif' + ); + }); +}); diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx new file mode 100644 index 0000000000..98d6b4ac1f --- /dev/null +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -0,0 +1,73 @@ +import { PauseIcon, PlayIcon } from '@codecademy/gamut-icons'; +import { css } from '@codecademy/gamut-styles'; +import styled from '@emotion/styled'; +import { useState } from 'react'; +import * as React from 'react'; +import Freezeframe from 'react-freezeframe'; + +import { Box } from '../../Box'; +import { FillButton } from '../../Button'; +import { HiddenText } from '../../HiddenText'; +import { imageStyles, PauseableImageProps } from '..'; + +export interface BaseImageProps extends PauseableImageProps {} + +export const Container = styled(Box)( + css({ + alignItems: 'center', + justifyContent: 'center', + height: '100%', + display: 'flex', + position: 'relative', + width: '100%', + [`> img, + > .react-freezeframe, + > .react-freezeframe img`]: { + maxWidth: '100%', + height: '100%', + }, + '.ff-container': { + height: '100%', + }, + '.ff-container .ff-canvas': { + transition: 'none', + }, + '.ff-loading-icon::before': { + display: 'none', + }, + }) +); + +export const PlayingImage = imageStyles; + +const StyledFreezeframe = styled(Freezeframe)(imageStyles); + +export const BaseImage: React.FC = ({ alt, ...rest }) => { + const [paused, setPaused] = useState(false); + + const [liveText, buttonLabel, Icon, Image] = paused + ? [`${alt}, paused`, 'Play animated image', PlayIcon, StyledFreezeframe] + : [`${alt}, playing`, 'Pause animated image', PauseIcon, PlayingImage]; + + return ( + + {alt} + {/* ensure proper fall back label if an empty string is given as alt */} + {alt ? liveText : buttonLabel} + setPaused(!paused)} + position="absolute" + right={0} + variant="secondary" + zIndex={1} + aria-label={buttonLabel} + > + + + + ); +}; + +export default BaseImage; diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx new file mode 100644 index 0000000000..5ef8be49b2 --- /dev/null +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -0,0 +1,32 @@ +import { setupRtl } from '@codecademy/gamut-tests'; +import { waitFor } from '@testing-library/react'; + +import { PausableImage } from '..'; + +const renderView = setupRtl(PausableImage); + +const createImg = (url: string) => ({ + alt: '', + src: url, +}); + +describe('PausableImage', () => { + it('renders a pausable image when the URL ends with .gif', async () => { + const { view } = await renderView({ + ...createImg('image.gif'), + }); + + // wait to find static image while loading pause ui + view.getByRole('img'); + // wait to find pause button + await waitFor(() => view.findByText('Pause animated image')); + }); + + it('renders a static image when the URL does not end with .gif', () => { + const { view } = renderView({ + ...createImg('image.svg'), + }); + + expect(view.getByRole('img')).toHaveAttribute('src', 'image.svg'); + }); +}); diff --git a/packages/gamut/src/PausableImage/index.tsx b/packages/gamut/src/PausableImage/index.tsx new file mode 100644 index 0000000000..ba812c0a65 --- /dev/null +++ b/packages/gamut/src/PausableImage/index.tsx @@ -0,0 +1,44 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import * as React from 'react'; + +const BaseImage = React.lazy(() => import('./BaseImage')); + +export interface PauseableImageProps { + src: string; + alt: string; +} +export const imageStyles = styled.img( + css({ + height: 'auto', + maxHeight: '100%', + maxWidth: '100%', + '&[src$=".svg"]': { + width: '100%', + }, + }) +); + +const StaticImage = imageStyles; + +export const PausableImage: React.FC = (props) => { + const staticImage = ; + + // Avoid rendering React.Suspense on the server until it's fully supported by React & our applications + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + return ( + <> + {isMounted && props.src?.endsWith('.gif') ? ( + + + + ) : ( + staticImage + )} + + ); +}; diff --git a/packages/gamut/src/index.tsx b/packages/gamut/src/index.tsx index 01628c9cde..991bbee735 100644 --- a/packages/gamut/src/index.tsx +++ b/packages/gamut/src/index.tsx @@ -37,6 +37,7 @@ export * from './ModalDeprecated'; export * from './Modals'; export * from './Overlay'; export * from './Pagination'; +export * from './PausableImage'; export * from './Popover'; export * from './PopoverContainer'; export * from './ProgressBar'; diff --git a/packages/gamut/src/typings/react-freezeframe.d.ts b/packages/gamut/src/typings/react-freezeframe.d.ts new file mode 100644 index 0000000000..83e1c91c0c --- /dev/null +++ b/packages/gamut/src/typings/react-freezeframe.d.ts @@ -0,0 +1 @@ +declare module 'react-freezeframe'; diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx new file mode 100644 index 0000000000..a53781782f --- /dev/null +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -0,0 +1,46 @@ +import { PausableImage } from '@codecademy/gamut'; +import title from '@codecademy/macros/lib/title.macro'; +import { PropsTable } from '@codecademy/storybook-addon-variance'; +import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; + +import { LinkTo } from '~styleguide/blocks'; + + + + + + {(args) => } + + + + + +## Usage + +```tsx +import { PausableImage } from '@codecademy/gamut'; + +; +``` + +## Color Modes + +PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. + +- Use the colormode changer of the top of the page to see the change diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index 241e29b955..ff1dd17500 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -1,4 +1,4 @@ -import { Markdown, Text } from '@codecademy/gamut/src'; +import { Column, LayoutGrid, Markdown, Text } from '@codecademy/gamut/src'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -66,6 +66,38 @@ A common override may be to change the font size of a Heading. +Img tags are overwitten by the PausableImage component because of the accessibility benefits it provides. +When provided with a Gif it allow the user to pause the gif. + + + ', + }} + > + + + ' + } + /> + + + ' + } + /> + + + + + If you need to override a link, iframe, or table, you do not need to provide the `skipDefaultOverides` prop. This prop is now only used for removing the default heading, paragraph, and list element overrides. From ea3aa04e44a0733102852919ba47d19b405e09de Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 9 May 2023 15:43:46 -0400 Subject: [PATCH 12/21] fix test --- .../src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx index ce07b69dba..336facae31 100644 --- a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx @@ -18,10 +18,10 @@ describe('BaseImage', () => { expect(view.getAllByRole('img')[0]).toHaveAttribute('src', 'image.gif'); }); - it('renders a paused image after clicking pause', async () => { + it('renders a paused image after clicking pause', () => { const { view } = renderView(); - await userEvent.click(view.getByRole('button')); + userEvent.click(view.getByRole('button')); expect(view.getAllByRole('img')[0]).toHaveAttribute( 'src', From dc6ae5ac03ef30adb7f76a389ee7484046db2d89 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 10 May 2023 11:04:27 -0400 Subject: [PATCH 13/21] prevent default of the container --- .../src/Markdown/__tests__/Markdown.test.tsx | 26 ++++++++++++++++++- .../src/PausableImage/BaseImage/index.tsx | 8 +++++- .../__tests__/PausableImage.test.tsx | 2 +- .../Molecules/PausableImage.stories.mdx | 23 +++++++++++++++- .../Organisms/Markdown/index.stories.mdx | 2 +- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx index aefc4b3018..c3a62d251b 100644 --- a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx +++ b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/no-distracting-elements */ import { setupRtl } from '@codecademy/gamut-tests'; -import { act, screen } from '@testing-library/react'; +import { act, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import * as React from 'react'; @@ -205,6 +205,30 @@ var test = true; screen.getByRole('img'); }); + it('renders a pausable image when the URL ends with .gif', async () => { + renderView({ + text: ``, + }); + + // wait to find static image while loading pause ui + screen.getByRole('img'); + // wait to find pause button + await waitFor(() => screen.findByText('Pause animated image')); + }); + + it(`doesn't renders a pausable image when the URL ends with .gif`, async () => { + renderView({ + text: ``, + }); + + // wait to find static image while loading pause ui + screen.getByRole('img'); + // wait to find pause button + await waitFor(() => + expect(screen.queryByText('Pause animated image')).toBeNull() + ); + }); + it('Allows passing in class names', () => { renderView({ text: `
# Cool
`, diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx index 98d6b4ac1f..9fcef2c408 100644 --- a/packages/gamut/src/PausableImage/BaseImage/index.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -57,7 +57,13 @@ export const BaseImage: React.FC = ({ alt, ...rest }) => { setPaused(!paused)} + onClick={(e) => { + setPaused(!paused); + // preventing the deafualt behavior of the image + // container from preventing the button image from + // being paused e.g. if the image is in a link + e.preventDefault(); + }} position="absolute" right={0} variant="secondary" diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx index 5ef8be49b2..cb03886f55 100644 --- a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -12,7 +12,7 @@ const createImg = (url: string) => ({ describe('PausableImage', () => { it('renders a pausable image when the URL ends with .gif', async () => { - const { view } = await renderView({ + const { view } = renderView({ ...createImg('image.gif'), }); diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index a53781782f..85dfbd5de7 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { PausableImage } from '@codecademy/gamut'; +import { Anchor, PausableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -39,6 +39,27 @@ import { PausableImage } from '@codecademy/gamut'; ; ``` +## Interactive Container + +If the image is wrapped in an interactive container, we prevent the default of the container whe clicking the toggle button. This is useful for when the image is wrapped in an anchor tag. + + + + {(args) => ( + + + + )} + + + ## Color Modes PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index ff1dd17500..ba05c37749 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -90,7 +90,7 @@ When provided with a Gif it allow the user to pause the gif. ' + ' demonstration of learning environment' } /> From ddc15a48b8c368a88c73836e54c0ef2a43849032 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 10 May 2023 14:30:26 -0400 Subject: [PATCH 14/21] update snapshot --- packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index 95ea4c64d8..1d685f6286 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -57,6 +57,7 @@ exports[`Gamut Exported Keys 1`] = ` "IconButton", "iFrameWrapper", "InfoTip", + "imageStyles", "Input", "InputStepper", "isClickableCrumb", @@ -78,6 +79,7 @@ exports[`Gamut Exported Keys 1`] = ` "omitProps", "Overlay", "Pagination", + "PausableImage", "Popover", "PopoverContainer", "ProgressBar", From 4cd949d2feba554a2fb31a643240f8a3b900b065 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Thu, 11 May 2023 11:32:15 -0400 Subject: [PATCH 15/21] update story --- packages/gamut/src/Markdown/libs/overrides/index.tsx | 2 +- .../styleguide/stories/Organisms/Markdown/index.stories.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gamut/src/Markdown/libs/overrides/index.tsx b/packages/gamut/src/Markdown/libs/overrides/index.tsx index 5dfc427e82..42ac9189f2 100644 --- a/packages/gamut/src/Markdown/libs/overrides/index.tsx +++ b/packages/gamut/src/Markdown/libs/overrides/index.tsx @@ -202,7 +202,7 @@ export const standardOverrides = [ }, ]; -// img tag override +// Allows for img tag override, which is separate because it doesn't have children export const createImgOverride = ( tagName: string, Override: OverrideSettings diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index ba05c37749..fd8dd3e09e 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -90,7 +90,7 @@ When provided with a Gif it allow the user to pause the gif. demonstration of learning environment' + 'demonstration of learning environment' } /> From f065edce774832e94128826156d5657359ca4cba Mon Sep 17 00:00:00 2001 From: vonbarown Date: Fri, 12 May 2023 09:38:59 -0400 Subject: [PATCH 16/21] remove double announcement --- .../src/Markdown/__tests__/Markdown.test.tsx | 2 +- .../src/PausableImage/BaseImage/index.tsx | 30 +++++++++++-------- .../Molecules/PausableImage.stories.mdx | 23 +------------- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx index c3a62d251b..94743eab43 100644 --- a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx +++ b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx @@ -216,7 +216,7 @@ var test = true; await waitFor(() => screen.findByText('Pause animated image')); }); - it(`doesn't renders a pausable image when the URL ends with .gif`, async () => { + it(`doesn't render a pausable image when the URL doesn't end with .gif`, async () => { renderView({ text: ``, }); diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx index 9fcef2c408..f74751d305 100644 --- a/packages/gamut/src/PausableImage/BaseImage/index.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -7,7 +7,6 @@ import Freezeframe from 'react-freezeframe'; import { Box } from '../../Box'; import { FillButton } from '../../Button'; -import { HiddenText } from '../../HiddenText'; import { imageStyles, PauseableImageProps } from '..'; export interface BaseImageProps extends PauseableImageProps {} @@ -45,25 +44,30 @@ const StyledFreezeframe = styled(Freezeframe)(imageStyles); export const BaseImage: React.FC = ({ alt, ...rest }) => { const [paused, setPaused] = useState(false); - const [liveText, buttonLabel, Icon, Image] = paused - ? [`${alt}, paused`, 'Play animated image', PlayIcon, StyledFreezeframe] - : [`${alt}, playing`, 'Pause animated image', PauseIcon, PlayingImage]; + const [liveText, buttonLabel, altFallBack, Icon, Image] = paused + ? [ + `${alt}, paused`, + 'Play animated image', + 'Playing animated image', + PlayIcon, + StyledFreezeframe, + ] + : [ + `${alt}, playing`, + 'Pause animated image', + 'Paused animated image', + PauseIcon, + PlayingImage, + ]; return ( - {alt} {/* ensure proper fall back label if an empty string is given as alt */} - {alt ? liveText : buttonLabel} + {alt { - setPaused(!paused); - // preventing the deafualt behavior of the image - // container from preventing the button image from - // being paused e.g. if the image is in a link - e.preventDefault(); - }} + onClick={() => setPaused(!paused)} position="absolute" right={0} variant="secondary" diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index 85dfbd5de7..a53781782f 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { Anchor, PausableImage } from '@codecademy/gamut'; +import { PausableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -39,27 +39,6 @@ import { PausableImage } from '@codecademy/gamut'; ; ``` -## Interactive Container - -If the image is wrapped in an interactive container, we prevent the default of the container whe clicking the toggle button. This is useful for when the image is wrapped in an anchor tag. - - - - {(args) => ( - - - - )} - - - ## Color Modes PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. From 724fbb34bd211df9a8545ce3f7fad045cc28142d Mon Sep 17 00:00:00 2001 From: vonbarown Date: Tue, 16 Apr 2024 13:30:25 -0400 Subject: [PATCH 17/21] re-add to test --- packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index ac28b5afc0..1d685f6286 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -56,6 +56,7 @@ exports[`Gamut Exported Keys 1`] = ` "HiddenText", "IconButton", "iFrameWrapper", + "InfoTip", "imageStyles", "Input", "InputStepper", From 11013b63556a7f2d17d1d3240ff1854f69670b73 Mon Sep 17 00:00:00 2001 From: vonbarown Date: Wed, 17 Apr 2024 09:40:02 -0400 Subject: [PATCH 18/21] fix render issues --- package.json | 4 +- .../src/Markdown/libs/overrides/index.tsx | 2 +- .../Organisms/Markdown/index.stories.mdx | 35 +---------------- yarn.lock | 38 +++++++------------ 4 files changed, 20 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index eaea380f7a..0b056ad867 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,9 @@ "ts-jest": "29.1.1", "ts-node": "10.9.1", "tslib": "2.4.0", - "typescript": "5.1.3" + "typescript": "5.1.3", + "react-freezeframe": "^5.0.2", + "freezeframe": "^5.0.2" }, "devDependencies": { "onchange": "^7.0.2", diff --git a/packages/gamut/src/Markdown/libs/overrides/index.tsx b/packages/gamut/src/Markdown/libs/overrides/index.tsx index 42ac9189f2..ac9591e695 100644 --- a/packages/gamut/src/Markdown/libs/overrides/index.tsx +++ b/packages/gamut/src/Markdown/libs/overrides/index.tsx @@ -205,7 +205,7 @@ export const standardOverrides = [ // Allows for img tag override, which is separate because it doesn't have children export const createImgOverride = ( tagName: string, - Override: OverrideSettings + Override: OverrideSettingsBase ) => ({ shouldProcessNode(node: HTMLToReactNode) { if (!Override) return false; diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index a99c4fc7e7..f8d689c506 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -66,39 +66,8 @@ A common override may be to change the font size of a Heading.
-Img tags are overwitten by the PausableImage component because of the accessibility benefits it provides. -When provided with a Gif it allow the user to pause the gif. - - - ', - }} - > - - - ' - } - /> - - - ' - } - /> - - - - - -If you need to override a link, iframe, or table, you also need to provide the `skipDefaultOverides` prop. +Img tags are overwitten by the `PausableImage` component because of the accessibility benefits it provides. +When provided with a Gif it will allow it to be be pausable. Date: Wed, 17 Apr 2024 09:47:15 -0400 Subject: [PATCH 19/21] rename component --- .../__tests__/__snapshots__/gamut.test.ts.snap | 2 +- packages/gamut/src/Markdown/index.tsx | 4 ++-- .../BaseImage/__tests__/BaseImage.test.tsx | 0 .../BaseImage/index.tsx | 0 .../__tests__/PausableImage.test.tsx | 8 ++++---- .../{PausableImage => PauseableImage}/index.tsx | 2 +- packages/gamut/src/index.tsx | 2 +- .../stories/Molecules/PausableImage.stories.mdx | 16 ++++++++-------- .../stories/Organisms/Markdown/index.stories.mdx | 4 ++-- 9 files changed, 19 insertions(+), 19 deletions(-) rename packages/gamut/src/{PausableImage => PauseableImage}/BaseImage/__tests__/BaseImage.test.tsx (100%) rename packages/gamut/src/{PausableImage => PauseableImage}/BaseImage/index.tsx (100%) rename packages/gamut/src/{PausableImage => PauseableImage}/__tests__/PausableImage.test.tsx (77%) rename packages/gamut/src/{PausableImage => PauseableImage}/index.tsx (92%) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index 1d685f6286..e9e80f6706 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -79,7 +79,7 @@ exports[`Gamut Exported Keys 1`] = ` "omitProps", "Overlay", "Pagination", - "PausableImage", + "PauseableImage", "Popover", "PopoverContainer", "ProgressBar", diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index bd9cbae8cf..e1b7aef01b 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -5,7 +5,7 @@ import { PureComponent } from 'react'; import * as React from 'react'; import sanitizeMarkdown from 'sanitize-markdown'; -import { PausableImage } from '../PausableImage'; +import { PauseableImage } from '../PauseableImage'; import { omitProps } from '../utils/omitProps'; import { createCodeBlockOverride, @@ -128,7 +128,7 @@ export class Markdown extends PureComponent { }), !skipDefaultOverrides.img && createImgOverride('img', { - component: PausableImage, + component: PauseableImage, }), ...overrides, ...standardOverrides, diff --git a/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PauseableImage/BaseImage/__tests__/BaseImage.test.tsx similarity index 100% rename from packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx rename to packages/gamut/src/PauseableImage/BaseImage/__tests__/BaseImage.test.tsx diff --git a/packages/gamut/src/PausableImage/BaseImage/index.tsx b/packages/gamut/src/PauseableImage/BaseImage/index.tsx similarity index 100% rename from packages/gamut/src/PausableImage/BaseImage/index.tsx rename to packages/gamut/src/PauseableImage/BaseImage/index.tsx diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx similarity index 77% rename from packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx rename to packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx index cb03886f55..94483d1641 100644 --- a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx +++ b/packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx @@ -1,17 +1,17 @@ import { setupRtl } from '@codecademy/gamut-tests'; import { waitFor } from '@testing-library/react'; -import { PausableImage } from '..'; +import { PauseableImage } from '..'; -const renderView = setupRtl(PausableImage); +const renderView = setupRtl(PauseableImage); const createImg = (url: string) => ({ alt: '', src: url, }); -describe('PausableImage', () => { - it('renders a pausable image when the URL ends with .gif', async () => { +describe('PauseableImage', () => { + it('renders a pauseable image when the URL ends with .gif', async () => { const { view } = renderView({ ...createImg('image.gif'), }); diff --git a/packages/gamut/src/PausableImage/index.tsx b/packages/gamut/src/PauseableImage/index.tsx similarity index 92% rename from packages/gamut/src/PausableImage/index.tsx rename to packages/gamut/src/PauseableImage/index.tsx index ba812c0a65..2308068bd0 100644 --- a/packages/gamut/src/PausableImage/index.tsx +++ b/packages/gamut/src/PauseableImage/index.tsx @@ -21,7 +21,7 @@ export const imageStyles = styled.img( const StaticImage = imageStyles; -export const PausableImage: React.FC = (props) => { +export const PauseableImage: React.FC = (props) => { const staticImage = ; // Avoid rendering React.Suspense on the server until it's fully supported by React & our applications diff --git a/packages/gamut/src/index.tsx b/packages/gamut/src/index.tsx index 991bbee735..ad303727c5 100644 --- a/packages/gamut/src/index.tsx +++ b/packages/gamut/src/index.tsx @@ -37,7 +37,7 @@ export * from './ModalDeprecated'; export * from './Modals'; export * from './Overlay'; export * from './Pagination'; -export * from './PausableImage'; +export * from './PauseableImage'; export * from './Popover'; export * from './PopoverContainer'; export * from './ProgressBar'; diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index a53781782f..1887c71b54 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { PausableImage } from '@codecademy/gamut'; +import { PauseableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -7,7 +7,7 @@ import { LinkTo } from '~styleguide/blocks'; - {(args) => } + {(args) => } - + ## Usage ```tsx -import { PausableImage } from '@codecademy/gamut'; +import { PauseableImage } from '@codecademy/gamut'; -; +; ``` ## Color Modes -PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. +PauseableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. - Use the colormode changer of the top of the page to see the change diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index f8d689c506..d2626b6243 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -66,8 +66,8 @@ A common override may be to change the font size of a Heading. -Img tags are overwitten by the `PausableImage` component because of the accessibility benefits it provides. -When provided with a Gif it will allow it to be be pausable. +Img tags are overwitten by the `PauseableImage` component because of the accessibility benefits it provides. +When provided with a Gif it will allow it to be be pauseable. Date: Wed, 17 Apr 2024 11:52:25 -0400 Subject: [PATCH 20/21] revert name change --- .../__tests__/__snapshots__/gamut.test.ts.snap | 2 +- packages/gamut/src/Markdown/index.tsx | 4 ++-- .../BaseImage/__tests__/BaseImage.test.tsx | 0 .../BaseImage/index.tsx | 4 ++-- .../__tests__/PausableImage.test.tsx | 8 ++++---- .../{PauseableImage => PausableImage}/index.tsx | 4 ++-- packages/gamut/src/index.tsx | 2 +- packages/styleguide/CHANGELOG.md | 2 +- .../stories/Molecules/PausableImage.stories.mdx | 16 ++++++++-------- .../stories/Organisms/Markdown/index.stories.mdx | 4 ++-- 10 files changed, 23 insertions(+), 23 deletions(-) rename packages/gamut/src/{PauseableImage => PausableImage}/BaseImage/__tests__/BaseImage.test.tsx (100%) rename packages/gamut/src/{PauseableImage => PausableImage}/BaseImage/index.tsx (94%) rename packages/gamut/src/{PauseableImage => PausableImage}/__tests__/PausableImage.test.tsx (77%) rename packages/gamut/src/{PauseableImage => PausableImage}/index.tsx (89%) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index e9e80f6706..1d685f6286 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -79,7 +79,7 @@ exports[`Gamut Exported Keys 1`] = ` "omitProps", "Overlay", "Pagination", - "PauseableImage", + "PausableImage", "Popover", "PopoverContainer", "ProgressBar", diff --git a/packages/gamut/src/Markdown/index.tsx b/packages/gamut/src/Markdown/index.tsx index e1b7aef01b..bd9cbae8cf 100644 --- a/packages/gamut/src/Markdown/index.tsx +++ b/packages/gamut/src/Markdown/index.tsx @@ -5,7 +5,7 @@ import { PureComponent } from 'react'; import * as React from 'react'; import sanitizeMarkdown from 'sanitize-markdown'; -import { PauseableImage } from '../PauseableImage'; +import { PausableImage } from '../PausableImage'; import { omitProps } from '../utils/omitProps'; import { createCodeBlockOverride, @@ -128,7 +128,7 @@ export class Markdown extends PureComponent { }), !skipDefaultOverrides.img && createImgOverride('img', { - component: PauseableImage, + component: PausableImage, }), ...overrides, ...standardOverrides, diff --git a/packages/gamut/src/PauseableImage/BaseImage/__tests__/BaseImage.test.tsx b/packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx similarity index 100% rename from packages/gamut/src/PauseableImage/BaseImage/__tests__/BaseImage.test.tsx rename to packages/gamut/src/PausableImage/BaseImage/__tests__/BaseImage.test.tsx diff --git a/packages/gamut/src/PauseableImage/BaseImage/index.tsx b/packages/gamut/src/PausableImage/BaseImage/index.tsx similarity index 94% rename from packages/gamut/src/PauseableImage/BaseImage/index.tsx rename to packages/gamut/src/PausableImage/BaseImage/index.tsx index f74751d305..8303ef002c 100644 --- a/packages/gamut/src/PauseableImage/BaseImage/index.tsx +++ b/packages/gamut/src/PausableImage/BaseImage/index.tsx @@ -7,9 +7,9 @@ import Freezeframe from 'react-freezeframe'; import { Box } from '../../Box'; import { FillButton } from '../../Button'; -import { imageStyles, PauseableImageProps } from '..'; +import { imageStyles, PausableImageProps } from '..'; -export interface BaseImageProps extends PauseableImageProps {} +export interface BaseImageProps extends PausableImageProps {} export const Container = styled(Box)( css({ diff --git a/packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx similarity index 77% rename from packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx rename to packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx index 94483d1641..cb03886f55 100644 --- a/packages/gamut/src/PauseableImage/__tests__/PausableImage.test.tsx +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -1,17 +1,17 @@ import { setupRtl } from '@codecademy/gamut-tests'; import { waitFor } from '@testing-library/react'; -import { PauseableImage } from '..'; +import { PausableImage } from '..'; -const renderView = setupRtl(PauseableImage); +const renderView = setupRtl(PausableImage); const createImg = (url: string) => ({ alt: '', src: url, }); -describe('PauseableImage', () => { - it('renders a pauseable image when the URL ends with .gif', async () => { +describe('PausableImage', () => { + it('renders a pausable image when the URL ends with .gif', async () => { const { view } = renderView({ ...createImg('image.gif'), }); diff --git a/packages/gamut/src/PauseableImage/index.tsx b/packages/gamut/src/PausableImage/index.tsx similarity index 89% rename from packages/gamut/src/PauseableImage/index.tsx rename to packages/gamut/src/PausableImage/index.tsx index 2308068bd0..635a321bcb 100644 --- a/packages/gamut/src/PauseableImage/index.tsx +++ b/packages/gamut/src/PausableImage/index.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; const BaseImage = React.lazy(() => import('./BaseImage')); -export interface PauseableImageProps { +export interface PausableImageProps { src: string; alt: string; } @@ -21,7 +21,7 @@ export const imageStyles = styled.img( const StaticImage = imageStyles; -export const PauseableImage: React.FC = (props) => { +export const PausableImage: React.FC = (props) => { const staticImage = ; // Avoid rendering React.Suspense on the server until it's fully supported by React & our applications diff --git a/packages/gamut/src/index.tsx b/packages/gamut/src/index.tsx index ad303727c5..991bbee735 100644 --- a/packages/gamut/src/index.tsx +++ b/packages/gamut/src/index.tsx @@ -37,7 +37,7 @@ export * from './ModalDeprecated'; export * from './Modals'; export * from './Overlay'; export * from './Pagination'; -export * from './PauseableImage'; +export * from './PausableImage'; export * from './Popover'; export * from './PopoverContainer'; export * from './ProgressBar'; diff --git a/packages/styleguide/CHANGELOG.md b/packages/styleguide/CHANGELOG.md index e1d434e140..807f0b04c7 100644 --- a/packages/styleguide/CHANGELOG.md +++ b/packages/styleguide/CHANGELOG.md @@ -1652,7 +1652,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features -- **PauseableImage:** :sparkles: Creating new pausable image component ([00c233d](https://github.com/Codecademy/gamut/commit/00c233d56498b819546b41c4dfba872618283044)) +- **PausableImage:** :sparkles: Creating new pausable image component ([00c233d](https://github.com/Codecademy/gamut/commit/00c233d56498b819546b41c4dfba872618283044)) ### [55.0.5](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@55.0.4...@codecademy/styleguide@55.0.5) (2022-03-08) diff --git a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx index 1887c71b54..a53781782f 100644 --- a/packages/styleguide/stories/Molecules/PausableImage.stories.mdx +++ b/packages/styleguide/stories/Molecules/PausableImage.stories.mdx @@ -1,4 +1,4 @@ -import { PauseableImage } from '@codecademy/gamut'; +import { PausableImage } from '@codecademy/gamut'; import title from '@codecademy/macros/lib/title.macro'; import { PropsTable } from '@codecademy/storybook-addon-variance'; import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; @@ -7,7 +7,7 @@ import { LinkTo } from '~styleguide/blocks'; - {(args) => } + {(args) => } - + ## Usage ```tsx -import { PauseableImage } from '@codecademy/gamut'; +import { PausableImage } from '@codecademy/gamut'; -; +; ``` ## Color Modes -PauseableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. +PausableImage components respond to the current Color Mode they are used in. The button and icon color will correctly display for the current color mode without any extra configuration. - Use the colormode changer of the top of the page to see the change diff --git a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx index d2626b6243..152d5932e2 100644 --- a/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx +++ b/packages/styleguide/stories/Organisms/Markdown/index.stories.mdx @@ -66,8 +66,8 @@ A common override may be to change the font size of a Heading. -Img tags are overwitten by the `PauseableImage` component because of the accessibility benefits it provides. -When provided with a Gif it will allow it to be be pauseable. +Img tags are overwitten by the `PausableImage` component because of the accessibility benefits it provides. +When provided with a Gif it will allow it to be paused. Date: Mon, 22 Apr 2024 14:02:00 -0400 Subject: [PATCH 21/21] fix test --- .../__tests__/__snapshots__/gamut.test.ts.snap | 2 +- .../src/Markdown/__tests__/Markdown.test.tsx | 7 +++++++ .../__tests__/PausableImage.test.tsx | 16 +++++++++------- .../gamut/src/typings/react-freezeframe.d.ts | 10 +++++++++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index 1d685f6286..1f51bcf874 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -56,8 +56,8 @@ exports[`Gamut Exported Keys 1`] = ` "HiddenText", "IconButton", "iFrameWrapper", - "InfoTip", "imageStyles", + "InfoTip", "Input", "InputStepper", "isClickableCrumb", diff --git a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx index 94743eab43..45b37cb8fd 100644 --- a/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx +++ b/packages/gamut/src/Markdown/__tests__/Markdown.test.tsx @@ -7,6 +7,13 @@ import * as React from 'react'; import { Markdown } from '../index'; +jest.mock('../../PausableImage/BaseImage', () => ({ src }: { src: string }) => ( + <> + + Pause animated image + +)); + const basicMarkdown = ` # Heading 1 diff --git a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx index cb03886f55..0d315d8cb4 100644 --- a/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx +++ b/packages/gamut/src/PausableImage/__tests__/PausableImage.test.tsx @@ -5,26 +5,28 @@ import { PausableImage } from '..'; const renderView = setupRtl(PausableImage); -const createImg = (url: string) => ({ - alt: '', - src: url, -}); +jest.mock('../BaseImage', () => ({ src }: { src: string }) => ( + <> + + Pause animated image + +)); describe('PausableImage', () => { it('renders a pausable image when the URL ends with .gif', async () => { const { view } = renderView({ - ...createImg('image.gif'), + src: 'image.gif', }); // wait to find static image while loading pause ui view.getByRole('img'); // wait to find pause button - await waitFor(() => view.findByText('Pause animated image')); + await waitFor(() => view.getByText('Pause animated image')); }); it('renders a static image when the URL does not end with .gif', () => { const { view } = renderView({ - ...createImg('image.svg'), + src: 'image.svg', }); expect(view.getByRole('img')).toHaveAttribute('src', 'image.svg'); diff --git a/packages/gamut/src/typings/react-freezeframe.d.ts b/packages/gamut/src/typings/react-freezeframe.d.ts index 83e1c91c0c..4ede58f7b3 100644 --- a/packages/gamut/src/typings/react-freezeframe.d.ts +++ b/packages/gamut/src/typings/react-freezeframe.d.ts @@ -1 +1,9 @@ -declare module 'react-freezeframe'; +declare module 'react-freezeframe' { + export interface FreezeframeProps { + className?: string; + src: string; + } + + // eslint-disable-next-line react/prefer-stateless-function + export default class Freezframe extends React.Component {} +}