Skip to content

Commit

Permalink
feat(ffe-cards-react): allow two icons on iconCard
Browse files Browse the repository at this point in the history
BREAKING CHANGE: removes and replaces "IconPosition"-prop and styling with "rightIcon" prop.
  • Loading branch information
dagfrode committed Jan 28, 2025
1 parent d262e43 commit f30f94d
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 36 deletions.
18 changes: 6 additions & 12 deletions packages/ffe-cards-react/src/IconCard/IconCard.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { IconCard } from './IconCard';
import { Icon } from '@sb1/ffe-icons-react';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { IconCard } from './IconCard';

const savingsIconXlarge =
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iNDgiPjxwYXRoIGQ9Ik0yNDMuMDc4LTE0MC4wMDFxLTIwLjIzMSAwLTM3LjgxNy0xMy4zNy0xNy41ODYtMTMuMzY5LTIzLjEwNi0zMi43MDctMjUtODcuNTM5LTQwLjk2NS0xNDguMjY2LTE1Ljk2Ni02MC43MjctMjUuMDE5LTEwNC42ODItOS4wNTItNDMuOTU1LTEyLjYxMS03Ni43OTEtMy41NTktMzIuODM2LTMuNTU5LTY0LjM2MyAwLTgzLjM1OCA1OC4yMzEtMTQxLjU4OCA1OC4yMy01OC4yMzEgMTQxLjc2OC01OC4yMzFoMjEwLjAwMXEyNy0zNiA2Ni01OCAzOC45OTktMjIgODMuOTk5LTIyIDE2LjUzOCAwIDI4LjI2OCAxMS43MzEgMTEuNzMxIDExLjczIDExLjczMSAyOC4yNjggMCA0LjA3Ny0xLjExNiA3Ljk2MS0xLjExNSAzLjg4NS0yLjM0NiA3LjczMS00LjM4NSAxMS43NjktOC40NjEgMjUuNDYyLTQuMDc3IDEzLjY5Mi03LjYxNiAzNC43N2wxMDQuMDc4IDEwNC4wNzdoNDYuNjE0cTEyLjM1NiAwIDIwLjYwMSA4LjI0NiA4LjI0NiA4LjI0NSA4LjI0NiAyMC42MDF2MTk0LjMwNXEwIDkuODc4LTUuMjQ2IDE3LjU5NS01LjI0NiA3LjcxNy0xNC45ODUgMTAuMjUxbC04OC44NDkgMjkuNTI4LTUzLjMwNSAxNzguMDFxLTYuMDI2IDE4Ljg0NS0yMS4wNzUgMzAuMTUzLTE1LjA0OSAxMS4zMDktMzQuNjE3IDExLjMwOWgtODQuMjI4cS0yMy41OTYgMC00MC42NDUtMTcuMDQ4LTE3LjA0OC0xNy4wNDktMTcuMDQ4LTQwLjY0NXYtMjIuMzA3SDM3OS45OTl2MjIuMzA3cTAgMjMuNTk2LTE3LjA0OCA0MC42NDUtMTcuMDQ5IDE3LjA0OC00MC42NDUgMTcuMDQ4aC03OS4yMjhabS0zLjg0Ni00NS4zODRoODMuMDc0cTUuMzg1IDAgOC44NDctMy40NjIgMy40NjItMy40NjIgMy40NjItOC44NDd2LTY3LjY5MWgyMTAuNzd2NjcuNjkxcTAgNS4zODUgMy40NjIgOC44NDcgMy40NjIgMy40NjIgOC44NDcgMy40NjJoODQuMjI4cTMuODQ3IDAgNy4xMTYtMi4zMDggMy4yNjktMi4zMDggNC44MDgtNi41MzlsNTkuOTIzLTE5OS45OTkgMTAwLjg0Ni0zNC42MTV2LTE2NS43NjloLTQ4LjkyM0w2MzQuNjE1LTcyNS42OTJxLjYxNS0xNyA0LjczMS00MC43MzEgNC4xMTUtMjMuNzMxIDExLjczLTQ5LjQ5OS0zNy45OTkgOS44NDYtNjguNDk5IDMyLjAzOC0zMC41IDIyLjE5Mi00NS4xMTUgNDkuMjY5SDMwMHEtNjQuMzYzIDAtMTA5LjQ4OSA0NS4xMjZRMTQ1LjM4NS02NDQuMzYyIDE0NS4zODUtNTgwcTAgNDEuMjMxIDIxLjAzOCAxNDEuNjkyIDIxLjAzOSAxMDAuNDYxIDYwLjExNiAyNDMuMzA3IDEuMTU0IDQuMjMxIDQuODA4IDYuOTIzIDMuNjU0IDIuNjkzIDcuODg1IDIuNjkzWk02NDAtNTI0LjYxNnExNC42OTIgMCAyNS4wMzgtMTAuMzQ2VDY3NS4zODQtNTYwcTAtMTQuNjkyLTEwLjM0Ni0yNS4wMzhUNjQwLTU5NS4zODRxLTE0LjY5MiAwLTI1LjAzOCAxMC4zNDZUNjA0LjYxNi01NjBxMCAxNC42OTIgMTAuMzQ2IDI1LjAzOFQ2NDAtNTI0LjYxNlptLTE0Mi42OTItMTAwcTkuNjYzIDAgMTYuMTc4LTYuNTY2UTUyMC02MzcuNzQ5IDUyMC02NDcuNDlxMC05Ljc0LTYuNTE0LTE2LjEyNS02LjUxNS02LjM4NC0xNi4xNzgtNi4zODRIMzQyLjY5MnEtOS42NjMgMC0xNi4xNzggNi41NjZRMzIwLTY1Ni44NjYgMzIwLTY0Ny4xMjVxMCA5Ljc0IDYuNTE0IDE2LjEyNSA2LjUxNSA2LjM4NCAxNi4xNzggNi4zODRoMTU0LjYxNlpNNDgwLTUwMC44NDZaIi8+PC9zdmc+';
Expand Down Expand Up @@ -61,26 +61,20 @@ describe('IconCard', () => {
).toBeTruthy();
});

it('should render icon on the right when modifier iconPosition="right', () => {
it('should render two icons, when icon and rightIcon prop set', () => {
render(
<IconCard
as="li"
iconPosition="right"
icon={<Icon fileUrl={savingsIconXlarge} size="xl" />}
rightIcon={<Icon fileUrl={savingsIconXlarge} size="xl" />}
>
{children}
</IconCard>,
);
const card = screen.getByRole('listitem');
const body = card.querySelector('.ffe-icon-card__body') as Element;
const icon = card.querySelector('.ffe-icon-card__icon') as Element;
const icons = card.querySelectorAll('.ffe-icon-card__icon');
expect(icons).toHaveLength(2);
expect(card.classList.contains('ffe-icon-card')).toBeTruthy();
expect(card.classList.contains('ffe-icon-card--right')).toBeTruthy();

expect(
body?.compareDocumentPosition(icon) &
Node.DOCUMENT_POSITION_FOLLOWING,
).toBeTruthy();
});

it('should render children as a function', () => {
Expand Down
49 changes: 47 additions & 2 deletions packages/ffe-cards-react/src/IconCard/IconCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Icon } from '@sb1/ffe-icons-react';
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { IconCard } from './IconCard';
import type { StoryObj, Meta } from '@storybook/react';
import { Icon } from '@sb1/ffe-icons-react';

const Custom: React.FC<React.ComponentProps<'div'>> = props => (
<div {...props}>
Expand Down Expand Up @@ -66,3 +66,48 @@ export const Condensed: Story = {
</IconCard>
),
};

export const TwoIcons: Story = {
args: {
as: 'div',
icon: <Icon fileUrl="./icons/open/300/xl/savings.svg" size="xl" />,
rightIcon: (
<Icon fileUrl="./icons/open/300/xl/chevron_right.svg" size="xl" />
),
},
render: args => (
<IconCard {...args}>
{({ CardName, Title, Subtext, Text }) => (
<>
<CardName>Kortnavn</CardName>
<Title>Tittel</Title>
<Subtext>En liten undertekst</Subtext>
<Text>Her kan man ha tekst</Text>
</>
)}
</IconCard>
),
};

export const TwoIconsCondensed: Story = {
args: {
as: 'div',
icon: <Icon fileUrl="./icons/open/300/lg/savings.svg" size="lg" />,
rightIcon: (
<Icon fileUrl="./icons/open/300/xl/chevron_right.svg" size="lg" />
),
condensed: true,
},
render: args => (
<IconCard {...args}>
{({ CardName, Title, Subtext, Text }) => (
<>
<CardName>Kortnavn</CardName>
<Title>Tittel</Title>
<Subtext>En liten undertekst</Subtext>
<Text>Her kan man ha tekst</Text>
</>
)}
</IconCard>
),
};
49 changes: 27 additions & 22 deletions packages/ffe-cards-react/src/IconCard/IconCard.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import classNames from 'classnames';
import React, { ElementType, ForwardedRef, ReactElement } from 'react';
import { CardName, Subtext, Text, Title, WithCardAction } from '../components';
import { fixedForwardRef } from '../fixedForwardRef';
import {
CardActionRenderProps,
CardRenderProps,
ComponentAsPropParams,
CardActionRenderProps,
} from '../types';
import classNames from 'classnames';
import { WithCardAction, Text, Subtext, Title, CardName } from '../components';
import { fixedForwardRef } from '../fixedForwardRef';

export type IconCardProps<As extends ElementType = 'div'> = Omit<
ComponentAsPropParams<As>,
'children'
> & {
/** Element of icon */
icon: ReactElement;
icon?: ReactElement;
rightIcon?: ReactElement;
/** Smaller icon and less space */
condensed?: boolean;
/** Position icon at left (default) or right of the card content */
iconPosition?: 'right' | 'left';
/** No margin on card */
noMargin?: boolean;
children:
Expand All @@ -33,9 +32,9 @@ function IconCardWithForwardRef<As extends ElementType>(
className,
condensed,
icon,
rightIcon,
noMargin,
children,
iconPosition,
...rest
} = props;

Expand All @@ -46,7 +45,6 @@ function IconCardWithForwardRef<As extends ElementType>(
'ffe-icon-card',
{ 'ffe-icon-card--condensed': condensed },
{ 'ffe-icon-card--no-margin': noMargin },
{ 'ffe-icon-card--right': iconPosition === 'right' },
className,
)}
{...(rest as Record<string, unknown>)}
Expand All @@ -67,23 +65,30 @@ function IconCardWithForwardRef<As extends ElementType>(
</div>
);

const iconElement = React.cloneElement(icon, {
...icon.props,
className: classNames(
'ffe-icon-card__icon',
icon.props.className,
),
});
const iconElement =
icon &&
React.cloneElement(icon, {
...icon.props,
className: classNames(
'ffe-icon-card__icon',
icon.props.className,
),
});

return iconPosition === 'right' ? (
<>
{bodyElement}
{iconElement}
</>
) : (
const rightIconElement =
rightIcon &&
React.cloneElement(rightIcon, {
...rightIcon.props,
className: classNames(
'ffe-icon-card__icon',
rightIcon.props.className,
),
});
return (
<>
{iconElement}
{bodyElement}
{rightIconElement}
</>
);
}}
Expand Down

0 comments on commit f30f94d

Please sign in to comment.