From 707a82294d12ed38a7897980e686f73032a3cbea Mon Sep 17 00:00:00 2001 From: HeleneKassandra Date: Mon, 11 Mar 2024 15:57:28 +0100 Subject: [PATCH 1/3] fix(component-overview): legg til detailListCard eksempler --- .../examples/lists/DetailListCard-clickable-rows.jsx | 12 ++++++++++++ .../lists/DetailListCard-minimal-clickable.jsx | 7 +++++++ component-overview/examples/lists/DetailListCard.jsx | 8 ++++++++ 3 files changed, 27 insertions(+) create mode 100644 component-overview/examples/lists/DetailListCard-clickable-rows.jsx create mode 100644 component-overview/examples/lists/DetailListCard-minimal-clickable.jsx create mode 100644 component-overview/examples/lists/DetailListCard.jsx diff --git a/component-overview/examples/lists/DetailListCard-clickable-rows.jsx b/component-overview/examples/lists/DetailListCard-clickable-rows.jsx new file mode 100644 index 0000000000..0cb58cb931 --- /dev/null +++ b/component-overview/examples/lists/DetailListCard-clickable-rows.jsx @@ -0,0 +1,12 @@ +import { DetailListCard, DetailListCardItem } from '@sb1/ffe-lists-react'; +import { Icon } from '@sb1/ffe-icons-react'; +import { LinkText } from '@sb1/ffe-core-react'; +import { PrimaryButton } from '@sb1/ffe-buttons-react'; + + + + + 1234 56 78912 }/> + + Tilfeldig} /> + diff --git a/component-overview/examples/lists/DetailListCard-minimal-clickable.jsx b/component-overview/examples/lists/DetailListCard-minimal-clickable.jsx new file mode 100644 index 0000000000..9eead92ed1 --- /dev/null +++ b/component-overview/examples/lists/DetailListCard-minimal-clickable.jsx @@ -0,0 +1,7 @@ +import { DetailListCard, DetailListCardItem } from '@sb1/ffe-lists-react'; +import { LinkText } from '@sb1/ffe-core-react'; + + + D} /> + + diff --git a/component-overview/examples/lists/DetailListCard.jsx b/component-overview/examples/lists/DetailListCard.jsx new file mode 100644 index 0000000000..699bcba729 --- /dev/null +++ b/component-overview/examples/lists/DetailListCard.jsx @@ -0,0 +1,8 @@ +import { DetailListCard, DetailListCardItem } from '@sb1/ffe-lists-react'; + + + + + + + From 39ed3adf5a9b2d4dab845375a59ee3a185dfc581 Mon Sep 17 00:00:00 2001 From: HeleneKassandra Date: Wed, 13 Mar 2024 13:09:58 +0100 Subject: [PATCH 2/3] feat(ffe-lists-react): legg til DetailListCard og DetailListCardItem komponent --- .../ffe-lists-react/src/DetailListCard.js | 21 +++++ .../src/DetailListCard.spec.js | 76 +++++++++++++++++++ .../ffe-lists-react/src/DetailListCardItem.js | 34 +++++++++ packages/ffe-lists-react/src/index.d.ts | 12 +++ packages/ffe-lists-react/src/index.js | 4 + 5 files changed, 147 insertions(+) create mode 100644 packages/ffe-lists-react/src/DetailListCard.js create mode 100644 packages/ffe-lists-react/src/DetailListCard.spec.js create mode 100644 packages/ffe-lists-react/src/DetailListCardItem.js diff --git a/packages/ffe-lists-react/src/DetailListCard.js b/packages/ffe-lists-react/src/DetailListCard.js new file mode 100644 index 0000000000..91a6752413 --- /dev/null +++ b/packages/ffe-lists-react/src/DetailListCard.js @@ -0,0 +1,21 @@ +import React from 'react'; +import classNames from 'classnames'; +import { node, string } from 'prop-types'; + +const DetailListCard = props => { + const { className, children, ...rest } = props; + + return ( +
+ {children} +
+ ); +}; + +DetailListCard.propTypes = { + /** Additional classnames */ + className: string, + children: node, +}; + +export default DetailListCard; diff --git a/packages/ffe-lists-react/src/DetailListCard.spec.js b/packages/ffe-lists-react/src/DetailListCard.spec.js new file mode 100644 index 0000000000..c27017fe3b --- /dev/null +++ b/packages/ffe-lists-react/src/DetailListCard.spec.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import DetailListCard from './DetailListCard'; +import DetailListCardItem from './DetailListCardItem'; + +const getWrapper = props => + shallow( + + + , + ); + +const getDetailListCardItemWrapper = props => + shallow( + , + ); + +describe('', () => { + it('renders without exploding', () => { + const wrapper = getWrapper(); + expect(wrapper.is('dl')).toBe(true); + }); + it('add classNames correctly', () => { + const wrapper = getWrapper({ className: 'test-class' }); + expect(wrapper.hasClass('ffe-detail-list-card')).toBe(true); + expect(wrapper.hasClass('test-class')).toBe(true); + }); +}); + +describe('', () => { + it('renders without exploding', () => { + const wrapper = getDetailListCardItemWrapper(); + expect(wrapper.is('div')).toBe(true); + expect(wrapper.hasClass('ffe-detail-list-card__item')).toBe(true); + }); + it('adds additional classNames correctly', () => { + const wrapper = getDetailListCardItemWrapper({ + className: 'test-class', + }); + expect(wrapper.hasClass('test-class')).toBe(true); + }); + + it('adds additional props correctly', () => { + const wrapper = getDetailListCardItemWrapper({ id: 'test-id' }); + expect(wrapper.prop('id')).toBe('test-id'); + }); + it('renders correct label content', () => { + const wrapper = getDetailListCardItemWrapper(); + expect( + wrapper.find('dt').hasClass('ffe-detail-list-card__item-label'), + ).toBe(true); + const wrapper2 = getDetailListCardItemWrapper({ + label: Test Label, + }); + expect(wrapper2.find('dt').contains(Test Label)).toBe( + true, + ); + }); + + it('renders correct value content', () => { + const wrapper = getDetailListCardItemWrapper(); + expect( + wrapper.find('dd').hasClass('ffe-detail-list-card__item-value'), + ).toBe(true); + const wrapper2 = getDetailListCardItemWrapper({ + value: Test Value, + }); + expect(wrapper2.find('dd').contains(Test Value)).toBe( + true, + ); + }); +}); diff --git a/packages/ffe-lists-react/src/DetailListCardItem.js b/packages/ffe-lists-react/src/DetailListCardItem.js new file mode 100644 index 0000000000..5f7af4d8f7 --- /dev/null +++ b/packages/ffe-lists-react/src/DetailListCardItem.js @@ -0,0 +1,34 @@ +import React from 'react'; +import classNames from 'classnames'; +import { string, node } from 'prop-types'; + +const DetailListCardItem = ({ className, label, value, ...rest }) => { + return ( +
+
+ {typeof label === 'string' + ? label + : React.cloneElement(label, { ...label.props })} +
+
+ {typeof value === 'string' + ? value + : React.cloneElement(value, { ...value.props })} +
+
+ ); +}; + +DetailListCardItem.propTypes = { + /** Additional classnames */ + className: string, + /** Content of the label / left column */ + label: node.isRequired, + /** Content of the value / right column */ + value: node.isRequired, +}; + +export default DetailListCardItem; diff --git a/packages/ffe-lists-react/src/index.d.ts b/packages/ffe-lists-react/src/index.d.ts index 1ee593bddb..f5dd24fbde 100644 --- a/packages/ffe-lists-react/src/index.d.ts +++ b/packages/ffe-lists-react/src/index.d.ts @@ -32,6 +32,18 @@ export interface DescriptionListProps extends BaseListProps { horizontal?: boolean; } +export interface DetailListCardItemProps + extends React.ComponentPropsWithoutRef<'div'> { + label: NonNullable; + value: NonNullable; +} + +export interface DetailListCard extends React.ComponentPropsWithoutRef<'dl'> { + children: + | NonNullable + | ((props: DetailListCardItemProps) => NonNullable); +} + declare class BulletList extends React.Component< BulletListProps & React.ComponentProps<'ul'>, any diff --git a/packages/ffe-lists-react/src/index.js b/packages/ffe-lists-react/src/index.js index 9b8a2f1241..d9675c4875 100644 --- a/packages/ffe-lists-react/src/index.js +++ b/packages/ffe-lists-react/src/index.js @@ -10,6 +10,8 @@ import DescriptionList from './DescriptionList'; import DescriptionListMultiCol from './DescriptionListMultiCol'; import DescriptionListTerm from './DescriptionListTerm'; import DescriptionListDescription from './DescriptionListDescription'; +import DetailListCard from './DetailListCard'; +import DetailListCardItem from './DetailListCardItem'; export { BulletList, @@ -24,6 +26,8 @@ export { DescriptionListMultiCol, DescriptionListTerm, DescriptionListDescription, + DetailListCard, + DetailListCardItem, }; export default BulletList; From ba789586b53ef1b027870c32279da220ff0eb7f9 Mon Sep 17 00:00:00 2001 From: HeleneKassandra Date: Wed, 13 Mar 2024 13:10:29 +0100 Subject: [PATCH 3/3] feat(ffe-lists): legg til detailListCard komponent styling --- packages/ffe-lists/less/detail-list-card.less | 65 +++++++++++++++++++ packages/ffe-lists/less/lists.less | 1 + packages/ffe-lists/less/theme.less | 6 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/ffe-lists/less/detail-list-card.less diff --git a/packages/ffe-lists/less/detail-list-card.less b/packages/ffe-lists/less/detail-list-card.less new file mode 100644 index 0000000000..141295cd64 --- /dev/null +++ b/packages/ffe-lists/less/detail-list-card.less @@ -0,0 +1,65 @@ +.ffe-detail-list-card { + background-color: var(--ffe-v-detail-list-card-background-color); + border-radius: var(--ffe-v-detail-list-card-border-radius); + font-family: var(--ffe-g-font); + font-variant-numeric: tabular-nums; + container-type: inline-size; + + &__item:not(:last-child) { + border-bottom: 1px solid var(--ffe-v-detail-list-card-border-color); + } + + &__item { + padding: var(--ffe-spacing-sm); + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: var(--ffe-spacing-xs); + overflow-wrap: anywhere; + text-wrap: balance; + + &:is(button) { + background-color: transparent; + border: 0; + width: 100%; + color: inherit; + } + + &:is(a) { + text-decoration: none; + color: inherit; + } + + &:is(:first-child) { + border-radius: var(--ffe-v-detail-list-card-border-radius) + var(--ffe-v-detail-list-card-border-radius) 0 0; + } + + &:is(:last-child) { + border-radius: 0 0 var(--ffe-v-detail-list-card-border-radius) + var(--ffe-v-detail-list-card-border-radius); + } + + &-label { + font-family: var(--ffe-g-font-heading-small); + color: var(--ffe-g-secondary-color); + } + + &-value { + margin: 0; // Removes the default dd-element margin when it breaks to a new line + display: flex; + align-items: center; + + & > a, + & > button { + min-width: 24px; // Secures a minimal size for clickable area in WCAG + } + } + + @container (width < 299px) { + flex-direction: column; + align-items: normal; + } + } +} diff --git a/packages/ffe-lists/less/lists.less b/packages/ffe-lists/less/lists.less index e9a2b4712a..9a60a22a7e 100644 --- a/packages/ffe-lists/less/lists.less +++ b/packages/ffe-lists/less/lists.less @@ -1,3 +1,4 @@ @import 'theme'; @import './regular-lists.less'; @import './description-list.less'; +@import './detail-list-card.less'; diff --git a/packages/ffe-lists/less/theme.less b/packages/ffe-lists/less/theme.less index 7392624e98..e41b5f0e55 100644 --- a/packages/ffe-lists/less/theme.less +++ b/packages/ffe-lists/less/theme.less @@ -4,7 +4,9 @@ --ffe-v-lists-description-description-color: var(--ffe-farge-svart); --ffe-v-lists-check-list-check-icon-color: var(--ffe-farge-skog); --ffe-v-lists-check-list-cross-icon-color: var(--ffe-farge-baer); - + --ffe-v-detail-list-card-background-color: var(--ffe-farge-hvit); + --ffe-v-detail-list-card-border-color: var(--ffe-farge-lysgraa); + --ffe-v-detail-list-card-border-radius: 16px; @media (prefers-color-scheme: dark) { .native { --ffe-v-lists-title-color: var(--ffe-farge-hvit); @@ -12,6 +14,8 @@ --ffe-farge-lysgraa ); --ffe-v-lists-check-list-check-icon-color: var(--ffe-farge-skog-70); + --ffe-v-detail-list-card-background-color: var(--ffe-farge-natt); + --ffe-v-detail-list-card-border-color: var(--ffe-farge-koksgraa); } } }