Skip to content

Commit

Permalink
feat(thumbnail-card-details): add keydown callback and default tabind…
Browse files Browse the repository at this point in the history
…ex (#3782)

* feat(thumbnail-card-details): add keydown callback

* feat(thumbnail-card-details): optionalize onKeyDownCallback

* feat(thumbnail-card-details): spec update

* feat(thumbnail-card-details): convert spec to RTL

* feat(thumbnail-card-details): update specs

* feat(thumbnail-card-details): rename prop
  • Loading branch information
jmcbgaston authored Jan 6, 2025
1 parent 1e8ef7f commit fc09211
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 127 deletions.
14 changes: 11 additions & 3 deletions src/components/thumbnail-card/ThumbnailCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Props = {
className?: string,
highlightOnHover?: boolean,
icon?: React.Node,
onKeyDown?: () => void,
subtitle?: React.Node,
thumbnail: React.Node,
title: React.Node,
Expand All @@ -20,11 +21,12 @@ type Props = {
const ThumbnailCard = ({
actionItem,
className = '',
icon,
highlightOnHover = false,
icon,
onKeyDown,
subtitle,
title,
thumbnail,
title,
...rest
}: Props) => (
<div
Expand All @@ -34,7 +36,13 @@ const ThumbnailCard = ({
{...rest}
>
<ThumbnailCardThumbnail thumbnail={thumbnail} />
<ThumbnailCardDetails actionItem={actionItem} icon={icon} subtitle={subtitle} title={title} />
<ThumbnailCardDetails
actionItem={actionItem}
icon={icon}
onKeyDown={onKeyDown}
subtitle={subtitle}
title={title}
/>
</div>
);

Expand Down
12 changes: 7 additions & 5 deletions src/components/thumbnail-card/ThumbnailCardDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,36 @@ import { useIsContentOverflowed } from '../../utils/dom';
type Props = {
actionItem?: React.Element<any>,
icon?: React.Node,
onKeyDown?: () => void,
subtitle?: React.Node,
title: React.Node,
};

type TitleProps = {
onKeyDown?: () => void,
title: React.Node,
};

const Title = ({ title }: TitleProps) => {
// $FlowFixMe
const Title = ({ title, onKeyDown }: TitleProps) => {
const textRef: { current: null | HTMLElement } = React.useRef(null);
const isTextOverflowed = useIsContentOverflowed(textRef);

return (
<Tooltip isDisabled={!isTextOverflowed} text={title}>
<div ref={textRef} className="thumbnail-card-title">
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */}
<div ref={textRef} role="link" className="thumbnail-card-title" tabIndex={0} onKeyDown={onKeyDown}>
{title}
</div>
</Tooltip>
);
};

const ThumbnailCardDetails = ({ actionItem, icon, subtitle, title }: Props) => (
const ThumbnailCardDetails = ({ actionItem, icon, subtitle, title, onKeyDown }: Props) => (
<div className="thumbnail-card-details">
{icon}
<div className="thumbnail-card-details-content">
<div className="ThumbnailCardDetails-bodyText">
<Title title={title} />
<Title title={title} onKeyDown={onKeyDown} />
{subtitle && <div className="thumbnail-card-subtitle">{subtitle}</div>}
</div>
{actionItem}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// @flow
import * as React from 'react';
import userEvent from '@testing-library/user-event';

import { mount, shallow } from 'enzyme';
import { render, screen } from '../../../test-utils/testing-library';

import * as libDom from '../../../utils/dom';

import ThumbnailCardDetails from '../ThumbnailCardDetails';

const getWrapper = (props = {}) => shallow(<ThumbnailCardDetails title={<div>Foo Bar!</div>} {...props} />);
const renderComponent = (props = {}) => render(<ThumbnailCardDetails title={<div>Foo Bar!</div>} {...props} />);

jest.mock('../../../utils/dom', () => ({ useIsContentOverflowed: jest.fn() }));

Expand All @@ -17,37 +17,49 @@ describe('components/thumbnail-card/ThumbnailCardDetails', () => {
});

test('should render', () => {
const wrapper = getWrapper();
const { container } = renderComponent();

expect(wrapper).toMatchSnapshot();
expect(container.querySelector('.thumbnail-card-details')).toBeInTheDocument();
});

test('should render icon', () => {
const icon = <img alt="icon" />;
const wrapper = getWrapper({ icon });
renderComponent({ icon });

expect(wrapper).toMatchSnapshot();
expect(screen.queryByAltText('icon')).toBeInTheDocument();
});

test('should render subtitle', () => {
const subtitle = <div>Subtitle!</div>;
const wrapper = getWrapper({ subtitle });
const { container } = renderComponent({ subtitle });

expect(wrapper).toMatchSnapshot();
expect(container.querySelector('.thumbnail-card-subtitle')).toBeInTheDocument();
});

test('should render actionItem', () => {
const actionItem = <button type="button">Click Me</button>;
const wrapper = getWrapper({ actionItem });
const actionText = 'Click Me';
const actionItem = <button type="button">{actionText}</button>;
renderComponent({ actionItem });

expect(wrapper).toMatchSnapshot();
expect(screen.getByText(actionText)).toBeInTheDocument();
});

test('should render a Tooltip if text is overflowed', () => {
test('should render a Tooltip if text is overflowed', async () => {
libDom.useIsContentOverflowed.mockReturnValue(true);
renderComponent();

await userEvent.tab();

expect(screen.getByRole('tooltip')).toBeInTheDocument();
});

test('should accept a keydown callback', async () => {
const someFunction = jest.fn();
const { container } = renderComponent({ onKeyDown: someFunction });
const title = container.querySelector('.thumbnail-card-title');

const wrapper = mount(<ThumbnailCardDetails title={<div>Foo Bar!</div>} />);
await userEvent.type(title, '{enter}');

expect(wrapper.find('Tooltip').length).toBe(1);
expect(someFunction).toHaveBeenCalled();
});
});

This file was deleted.

0 comments on commit fc09211

Please sign in to comment.