diff --git a/component-overview/examples/cards/IllustrationCard-illustrationPositioned.jsx b/component-overview/examples/cards/IllustrationCard-illustrationPositioned.jsx new file mode 100644 index 0000000000..9a58c86cf8 --- /dev/null +++ b/component-overview/examples/cards/IllustrationCard-illustrationPositioned.jsx @@ -0,0 +1,315 @@ +import { IllustrationCard } from '@sb1/ffe-cards-react'; +import React from 'react'; + +() => { + const illustration = ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + + return ( + + {({ CardName, Title, Subtext, Text }) => ( + <> + Kortnavn + Tittel + En liten undertekst + Her kan man ha tekst + + )} + + ); +}; diff --git a/packages/ffe-cards-react/src/IconCard/IconCard.spec.tsx b/packages/ffe-cards-react/src/IconCard/IconCard.spec.tsx index b39b1bdab4..ff08e94141 100644 --- a/packages/ffe-cards-react/src/IconCard/IconCard.spec.tsx +++ b/packages/ffe-cards-react/src/IconCard/IconCard.spec.tsx @@ -7,19 +7,18 @@ const savingsIconXlarge = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iNDgiPjxwYXRoIGQ9Ik0yNDMuMDc4LTE0MC4wMDFxLTIwLjIzMSAwLTM3LjgxNy0xMy4zNy0xNy41ODYtMTMuMzY5LTIzLjEwNi0zMi43MDctMjUtODcuNTM5LTQwLjk2NS0xNDguMjY2LTE1Ljk2Ni02MC43MjctMjUuMDE5LTEwNC42ODItOS4wNTItNDMuOTU1LTEyLjYxMS03Ni43OTEtMy41NTktMzIuODM2LTMuNTU5LTY0LjM2MyAwLTgzLjM1OCA1OC4yMzEtMTQxLjU4OCA1OC4yMy01OC4yMzEgMTQxLjc2OC01OC4yMzFoMjEwLjAwMXEyNy0zNiA2Ni01OCAzOC45OTktMjIgODMuOTk5LTIyIDE2LjUzOCAwIDI4LjI2OCAxMS43MzEgMTEuNzMxIDExLjczIDExLjczMSAyOC4yNjggMCA0LjA3Ny0xLjExNiA3Ljk2MS0xLjExNSAzLjg4NS0yLjM0NiA3LjczMS00LjM4NSAxMS43NjktOC40NjEgMjUuNDYyLTQuMDc3IDEzLjY5Mi03LjYxNiAzNC43N2wxMDQuMDc4IDEwNC4wNzdoNDYuNjE0cTEyLjM1NiAwIDIwLjYwMSA4LjI0NiA4LjI0NiA4LjI0NSA4LjI0NiAyMC42MDF2MTk0LjMwNXEwIDkuODc4LTUuMjQ2IDE3LjU5NS01LjI0NiA3LjcxNy0xNC45ODUgMTAuMjUxbC04OC44NDkgMjkuNTI4LTUzLjMwNSAxNzguMDFxLTYuMDI2IDE4Ljg0NS0yMS4wNzUgMzAuMTUzLTE1LjA0OSAxMS4zMDktMzQuNjE3IDExLjMwOWgtODQuMjI4cS0yMy41OTYgMC00MC42NDUtMTcuMDQ4LTE3LjA0OC0xNy4wNDktMTcuMDQ4LTQwLjY0NXYtMjIuMzA3SDM3OS45OTl2MjIuMzA3cTAgMjMuNTk2LTE3LjA0OCA0MC42NDUtMTcuMDQ5IDE3LjA0OC00MC42NDUgMTcuMDQ4aC03OS4yMjhabS0zLjg0Ni00NS4zODRoODMuMDc0cTUuMzg1IDAgOC44NDctMy40NjIgMy40NjItMy40NjIgMy40NjItOC44NDd2LTY3LjY5MWgyMTAuNzd2NjcuNjkxcTAgNS4zODUgMy40NjIgOC44NDcgMy40NjIgMy40NjIgOC44NDcgMy40NjJoODQuMjI4cTMuODQ3IDAgNy4xMTYtMi4zMDggMy4yNjktMi4zMDggNC44MDgtNi41MzlsNTkuOTIzLTE5OS45OTkgMTAwLjg0Ni0zNC42MTV2LTE2NS43NjloLTQ4LjkyM0w2MzQuNjE1LTcyNS42OTJxLjYxNS0xNyA0LjczMS00MC43MzEgNC4xMTUtMjMuNzMxIDExLjczLTQ5LjQ5OS0zNy45OTkgOS44NDYtNjguNDk5IDMyLjAzOC0zMC41IDIyLjE5Mi00NS4xMTUgNDkuMjY5SDMwMHEtNjQuMzYzIDAtMTA5LjQ4OSA0NS4xMjZRMTQ1LjM4NS02NDQuMzYyIDE0NS4zODUtNTgwcTAgNDEuMjMxIDIxLjAzOCAxNDEuNjkyIDIxLjAzOSAxMDAuNDYxIDYwLjExNiAyNDMuMzA3IDEuMTU0IDQuMjMxIDQuODA4IDYuOTIzIDMuNjU0IDIuNjkzIDcuODg1IDIuNjkzWk02NDAtNTI0LjYxNnExNC42OTIgMCAyNS4wMzgtMTAuMzQ2VDY3NS4zODQtNTYwcTAtMTQuNjkyLTEwLjM0Ni0yNS4wMzhUNjQwLTU5NS4zODRxLTE0LjY5MiAwLTI1LjAzOCAxMC4zNDZUNjA0LjYxNi01NjBxMCAxNC42OTIgMTAuMzQ2IDI1LjAzOFQ2NDAtNTI0LjYxNlptLTE0Mi42OTItMTAwcTkuNjYzIDAgMTYuMTc4LTYuNTY2UTUyMC02MzcuNzQ5IDUyMC02NDcuNDlxMC05Ljc0LTYuNTE0LTE2LjEyNS02LjUxNS02LjM4NC0xNi4xNzgtNi4zODRIMzQyLjY5MnEtOS42NjMgMC0xNi4xNzggNi41NjZRMzIwLTY1Ni44NjYgMzIwLTY0Ny4xMjVxMCA5Ljc0IDYuNTE0IDE2LjEyNSA2LjUxNSA2LjM4NCAxNi4xNzggNi4zODRoMTU0LjYxNlpNNDgwLTUwMC44NDZaIi8+PC9zdmc+'; const children =
Hello world
; -const TEST_ID = 'test-id'; describe('IconCard', () => { it('should render correct class and contain a div with body class', () => { render( } > {children} , ); - const card = screen.getByTestId(TEST_ID); + const card = screen.getByRole('listitem'); expect(card.classList.contains('ffe-icon-card')).toBeTruthy(); expect(card.querySelector('.ffe-icon-card__body')).toBeTruthy(); }); @@ -27,7 +26,7 @@ describe('IconCard', () => { it('should render icon, with an added class', () => { render( { {children} , ); - const card = screen.getByTestId(TEST_ID); + const card = screen.getByRole('listitem'); const icon = card.querySelector('.ffe-icons'); expect(icon?.classList.contains('ffe-icon-card__icon')).toBe(true); expect(icon?.classList.contains('my-custom-class')).toBe(true); @@ -48,14 +47,14 @@ describe('IconCard', () => { it('should add modifying classes when modifiers are given', () => { render( } > {children} , ); - const card = screen.getByTestId(TEST_ID); + const card = screen.getByRole('listitem'); expect(card.classList.contains('ffe-icon-card')).toBeTruthy(); expect( card.classList.contains('ffe-icon-card--condensed'), @@ -65,38 +64,36 @@ describe('IconCard', () => { it('should render icon on the right when modifier iconPosition="right', () => { render( } > {children} , ); - const card = screen.getByTestId(TEST_ID); + 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; expect(card.classList.contains('ffe-icon-card')).toBeTruthy(); + expect(card.classList.contains('ffe-icon-card--right')).toBeTruthy(); - const icon = card.querySelector('.ffe-icon-card__icon'); - const body = card.querySelector('.ffe-icon-card__body'); - - if (icon && body) { - expect( - body?.compareDocumentPosition(icon) & - Node.DOCUMENT_POSITION_FOLLOWING, - ).toBeTruthy(); - } + expect( + body?.compareDocumentPosition(icon) & + Node.DOCUMENT_POSITION_FOLLOWING, + ).toBeTruthy(); }); it('should render children as a function', () => { render( } children={Components => ( Hello world )} />, ); - const card = screen.getByTestId(TEST_ID); + const card = screen.getByRole('listitem'); const p = card.querySelector('p'); expect(p?.classList.contains('ffe-card-body__text')).toBeTruthy(); expect(p?.textContent).toEqual('Hello world'); @@ -105,14 +102,14 @@ describe('IconCard', () => { it('should render my custom class', () => { render( } className="my-custom-class" > {children} , ); - const card = screen.getByTestId(TEST_ID); + const card = screen.getByRole('listitem'); expect(card.classList.contains('ffe-icon-card')).toBeTruthy(); expect(card.classList.contains('my-custom-class')).toBeTruthy(); }); diff --git a/packages/ffe-cards-react/src/IconCard/IconCard.tsx b/packages/ffe-cards-react/src/IconCard/IconCard.tsx index 87eec8a07c..0fc2f0bffd 100644 --- a/packages/ffe-cards-react/src/IconCard/IconCard.tsx +++ b/packages/ffe-cards-react/src/IconCard/IconCard.tsx @@ -25,6 +25,7 @@ function IconCardWithForwardRef( ) { const { className, condensed, icon, children, iconPosition, ...rest } = props; + return ( ( ref={ref} > {({ CardAction }) => { - const content = [ - React.cloneElement(icon, { - ...icon.props, - key: 'icon', - className: classNames( - 'ffe-icon-card__icon', - icon.props.className, - ), - }), -
+ const bodyElement = ( +
{typeof children === 'function' ? children({ Text, @@ -57,11 +50,26 @@ function IconCardWithForwardRef( CardAction, }) : children} -
, - ]; - return ( +
+ ); + + const iconElement = React.cloneElement(icon, { + ...icon.props, + className: classNames( + 'ffe-icon-card__icon', + icon.props.className, + ), + }); + + return iconPosition === 'right' ? ( + <> + {bodyElement} + {iconElement} + + ) : ( <> - {iconPosition === 'right' ? content.reverse() : content} + {iconElement} + {bodyElement} ); }} diff --git a/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.spec.tsx b/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.spec.tsx index b05acaab6e..5b15f3167b 100644 --- a/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.spec.tsx +++ b/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.spec.tsx @@ -13,288 +13,6 @@ const illustration = ( fill="none" aria-hidden={true} > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { const listitem = screen.getByRole('listitem'); expect(listitem).toBe(ref.current); }); + + it('should render illustration on the right when modifier iconPosition="right', () => { + render( + + {children} + , + ); + const card = screen.getByRole('listitem'); + const bodyElement = card.querySelector( + '.ffe-illustration-card__body', + ) as Element; + const illustrationElement = card.querySelector( + '.ffe-illustration-card__illustration', + ) as Element; + expect(card.classList.contains('ffe-illustration-card')).toBeTruthy(); + expect( + card.classList.contains('ffe-illustration-card--right'), + ).toBeTruthy(); + + expect( + bodyElement?.compareDocumentPosition(illustrationElement) & + Node.DOCUMENT_POSITION_FOLLOWING, + ).toBeTruthy(); + }); }); diff --git a/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.tsx b/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.tsx index 2c2d252e68..5271e9ddb6 100644 --- a/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.tsx +++ b/packages/ffe-cards-react/src/IllustrationCard/IllustrationCard.tsx @@ -12,6 +12,8 @@ export type IllustrationCardProps = Omit< img: ReactElement; /** Smaller illustration and less space */ condensed?: boolean; + /** Position illustration at left (default) or right of the card content */ + illustrationPosition?: 'right' | 'left'; children: | React.ReactNode | ((cardRenderProps: CardRenderProps) => React.ReactNode); @@ -21,20 +23,31 @@ function IllustrationCardWithForwardRef( props: IllustrationCardProps, ref: ForwardedRef, ) { - const { className, condensed, img, children, ...rest } = props; + const { + className, + condensed, + img, + illustrationPosition, + children, + ...rest + } = props; return ( )} ref={ref} > - {({ CardAction }) => ( - <> + {({ CardAction }) => { + const illustrationElement = (
( > {img}
+ ); + + const bodyElement = (
{typeof children === 'function' ? children({ @@ -53,8 +69,20 @@ function IllustrationCardWithForwardRef( }) : children}
- - )} + ); + + return illustrationPosition === 'right' ? ( + <> + {bodyElement} + {illustrationElement} + + ) : ( + <> + {illustrationElement} + {bodyElement} + + ); + }}
); } diff --git a/packages/ffe-cards/less/icon-card.less b/packages/ffe-cards/less/icon-card.less index 61e6c84775..868864ddb7 100644 --- a/packages/ffe-cards/less/icon-card.less +++ b/packages/ffe-cards/less/icon-card.less @@ -12,28 +12,21 @@ grid-template-columns: auto 1fr; align-items: center; padding: var(--ffe-spacing-md); + gap: var(--ffe-spacing-xs); - & > &__icon { - color: var(--ffe-v-cards-icon-color); - margin: 0 var(--ffe-spacing-lg) 0 var(--ffe-spacing-xs); - } - - &.ffe-icon-card--right { - .ffe-icon-card__icon { - justify-self: end; - margin: 0 var(--ffe-spacing-xs) 0 var(--ffe-spacing-lg); - } + &--right { + grid-template-columns: 1fr auto; + justify-content: space-between; } @media (min-width: @breakpoint-md) { - .ffe-icon-card__icon { - margin: 0 var(--ffe-spacing-md) 0; + gap: var(--ffe-spacing-md); + &--condensed { + gap: var(--ffe-spacing-xs); } } -} -.ffe-icon-card--condensed { .ffe-icon-card__icon { - margin: 0 var(--ffe-spacing-sm) 0 0; + color: var(--ffe-v-cards-icon-color); } } diff --git a/packages/ffe-cards/less/illustration-card.less b/packages/ffe-cards/less/illustration-card.less index 79532c290a..bb60f662a9 100644 --- a/packages/ffe-cards/less/illustration-card.less +++ b/packages/ffe-cards/less/illustration-card.less @@ -18,4 +18,9 @@ column-gap: var(--ffe-spacing-sm); padding: var(--ffe-spacing-sm); } + + &--right { + grid-template-columns: 1fr auto; + justify-content: space-between; + } }