From 87d01a8ca6fb96ab67ce5c984b469da81cd83f3d Mon Sep 17 00:00:00 2001 From: Gabriel Maschke Date: Fri, 14 Jul 2023 14:22:21 -0300 Subject: [PATCH 1/2] feat(card): make list item clickable in plan card --- packages/yoga/src/Card/web/PlanCard/List.jsx | 21 +- .../src/Card/web/PlanCard/PlanCard.test.jsx | 41 +- .../__snapshots__/PlanCard.test.jsx.snap | 443 ++++++++++++++++++ 3 files changed, 500 insertions(+), 5 deletions(-) diff --git a/packages/yoga/src/Card/web/PlanCard/List.jsx b/packages/yoga/src/Card/web/PlanCard/List.jsx index d0288ad366..9c94cf22ac 100644 --- a/packages/yoga/src/Card/web/PlanCard/List.jsx +++ b/packages/yoga/src/Card/web/PlanCard/List.jsx @@ -4,6 +4,7 @@ import { string, node, shape, oneOfType, func } from 'prop-types'; import Text from '../../../Text'; import theme from '../../../Theme/helpers/themeReader'; +import Box from '../../../Box'; const { card, cardweb } = theme.components; @@ -31,11 +32,20 @@ const Item = styled.li` } `; -const Wrapper = styled.div` +const Wrapper = styled(Box)` display: flex; min-width: 0; align-items: center; + ${props => + props.as === 'button' && + css` + border: none; + padding: 0; + background: transparent; + cursor: pointer; + `} + svg { flex-shrink: 0; } @@ -77,9 +87,9 @@ const Button = styled.button` `; const ListItem = withTheme( - ({ text, icon: Icon, buttonProps, theme: yogaTheme }) => ( + ({ text, icon: Icon, buttonProps, theme: yogaTheme, onClick }) => ( - + {Icon && ( {isValidElement(Icon) ? ( @@ -105,17 +115,20 @@ ListItem.displayName = 'PlanCard.ListItem'; Button.displayName = 'PlanCard.ListButton'; ListItem.propTypes = { - text: string.isRequired, + text: oneOfType([string, node]).isRequired, /** an icon to be displayed on the begin of the item */ icon: oneOfType([node, func]), /** if provided displays a button below the item text. It accepts all button * element props */ buttonProps: shape({}), + /** if provided makes the item clickable */ + onClick: func, }; ListItem.defaultProps = { icon: undefined, buttonProps: {}, + onClick: undefined, }; export { List, ListItem }; diff --git a/packages/yoga/src/Card/web/PlanCard/PlanCard.test.jsx b/packages/yoga/src/Card/web/PlanCard/PlanCard.test.jsx index 8065953c28..dec60073d6 100644 --- a/packages/yoga/src/Card/web/PlanCard/PlanCard.test.jsx +++ b/packages/yoga/src/Card/web/PlanCard/PlanCard.test.jsx @@ -7,7 +7,7 @@ import PlanCard from '.'; describe('', () => { const buttonOnClickMock = jest.fn(); - const renderPlan = () => + const renderPlan = ({ clickableItems } = {}) => render( @@ -31,6 +31,7 @@ describe('', () => { /> } text="gyms and studios" + onClick={clickableItems && jest.fn()} /> ', () => { as: 'a', onClick: buttonOnClickMock, }} + onClick={clickableItems && jest.fn()} /> @@ -58,6 +60,37 @@ describe('', () => { expect(buttonOnClickMock).toHaveBeenCalled(); }); + + it('should make list item clickable', () => { + const itemClickMock = jest.fn(); + + const { getByRole } = render( + + + + + + } + text="gyms and studios" + onClick={itemClickMock} + /> + + + + , + ); + + fireEvent.click(getByRole('button', { label: 'gyms and studios' })); + + expect(itemClickMock).toHaveBeenCalled(); + }); }); describe('Snapshots', () => { @@ -151,5 +184,11 @@ describe('', () => { expect(container).toMatchSnapshot(); }); + + it('should render list item content as button', () => { + const { container } = renderPlan({ clickableItems: true }); + + expect(container).toMatchSnapshot(); + }); }); }); diff --git a/packages/yoga/src/Card/web/PlanCard/__snapshots__/PlanCard.test.jsx.snap b/packages/yoga/src/Card/web/PlanCard/__snapshots__/PlanCard.test.jsx.snap index 8f9294480f..46cce17349 100644 --- a/packages/yoga/src/Card/web/PlanCard/__snapshots__/PlanCard.test.jsx.snap +++ b/packages/yoga/src/Card/web/PlanCard/__snapshots__/PlanCard.test.jsx.snap @@ -760,6 +760,449 @@ exports[` Snapshots should match snapshot with variant 1`] = ` `; +exports[` Snapshots should render list item content as button 1`] = ` +.c16 { + width: 16px; + height: 16px; +} + +.c20 { + box-sizing: border-box; + text-align: center; + outline: none; + -webkit-transition: all 0.2s; + transition: all 0.2s; + cursor: pointer; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + width: 100%; + height: 48px; + padding-left: 24px; + padding-right: 24px; + background-color: #D8385E; + border: none; + border-radius: 9999px; + color: #FFFFFF; + font-size: 16px; + font-weight: 500; + font-family: Rubik; + -webkit-letter-spacing: normal; + -moz-letter-spacing: normal; + -ms-letter-spacing: normal; + letter-spacing: normal; + line-height: 1; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c20 svg { + width: 24px; + height: 24px; + fill: #FFFFFF; + margin-right: 8px; + -webkit-transition: fill 0.2s; + transition: fill 0.2s; +} + +.c20:not([disabled]):hover, +.c20:not([disabled]):focus { + box-shadow: 0 4px 8px rgba(216,56,94,0.45); +} + +.c20:active { + background-color: rgba(216,56,94,0.75); + color: #FFFFFF; +} + +.c20:active svg { + fill: #FFFFFF; +} + +.c9 { + margin: 0; + padding: 0; + font-size: 24px; + line-height: 32px; + font-weight: 500; + font-family: Rubik; + color: #231B22; +} + +.c19 { + margin-top: 24px; +} + +.c6 { + margin: 0; + padding: 0; + font-size: 12px; + line-height: 16px; + font-weight: 400; + font-family: Rubik; + color: #231B22; + text-transform: uppercase; + margin-bottom: 8px; + color: #6B6B78; + font-weight: 500; +} + +.c11 { + width: 100%; + border-width: 0px; + border-left-width: 0px; + border-bottom-width: 1px; + border-color: #D7D7E0; +} + +.c5 { + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.c7 { + margin: 0; + padding: 0; + font-size: 16px; + font-weight: 500; + font-family: Rubik; + color: #231B22; + color: #231B22; + margin-bottom: 8px; + line-height: 24px; +} + +.c8 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + margin-bottom: 24px; +} + +.c10 { + margin: 0; + padding: 0; + font-size: 16px; + font-weight: 500; + font-family: Rubik; + color: #231B22; + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; +} + +.c0 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + max-width: 312px; + overflow: hidden; + padding: 56px 24px 24px 24px; + border: 1px solid #D7D7E0; + border-radius: 16px; + background-color: #FFFFFF; +} + +.c1 { + position: absolute; + top: 0; + left: 0; + display: inline-block; + width: 100%; + height: 4px; + background-color: #710252; +} + +.c1::before { + position: absolute; + height: 112px; + width: 112px; + content: ''; + background: radial-gradient( 50% 50% at 50% 50%, #FFFFFF 0%, transparent 100% ); + border-radius: 50%; + left: 24px; + top: -84px; + opacity: 0.8; +} + +.c2 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-style: solid; + padding: 0 4px 0 4px; + color: #5340C9; + border-radius: 4px; + border-width: 1px; + border-color: #5340C9; + font-size: 12px; + line-height: 16px; + font-weight: 500; +} + +.c3 { + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #E0DFFF; + color: #231B22; + border-radius: 4px; + border-color: #E0DFFF; + font-size: 12px; + font-weight: 500; +} + +.c4 { + position: absolute; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + top: 28px; + left: 24px; +} + +.c12 { + margin: 24px 0 0; + padding: 0; + list-style: none; +} + +.c15 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + margin-right: 8px; +} + +.c13:not(:last-child) { + margin-bottom: 16px; +} + +.c14 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + min-width: 0; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border: none; + padding: 0; + background: transparent; + cursor: pointer; +} + +.c14 svg { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.c17 { + margin: 0; + padding: 0; + font-size: 14px; + line-height: 20px; + font-weight: 400; + font-family: Rubik; + color: #231B22; + display: inline-block; + height: 100%; + vertical-align: middle; + color: #231B22; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.c18 { + display: block; + padding: 0; + margin-top: 12px; + width: 100%; + -webkit-letter-spacing: normal; + -moz-letter-spacing: normal; + -ms-letter-spacing: normal; + letter-spacing: normal; + background-color: transparent; + border: none; + font-family: Rubik; + font-size: 12px; + font-weight: 500; + color: #231B22; + cursor: pointer; + -webkit-text-decoration: none; + text-decoration: none; + text-align: left; + outline: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +
+
+ +
+ Recommended Plan +
+
+

+ plan +

+

+ Basic +

+
+ + $ + + + 99.90 + + + /month + +
+
+

+ Get access to +

+
    +
  • + +
  • +
  • + + + button + +
  • +
+
+
+ +
+
+
+`; + exports[` Snapshots should render the discount 1`] = ` .c2 { margin: 0; From 5845523425325a78f71ac90ce709fe97d41866d7 Mon Sep 17 00:00:00 2001 From: Gabriel Maschke Date: Mon, 17 Jul 2023 14:14:15 -0300 Subject: [PATCH 2/2] feat: add type "button" --- packages/yoga/src/Card/web/PlanCard/List.jsx | 48 +++++++++++-------- .../__snapshots__/PlanCard.test.jsx.snap | 2 + 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/yoga/src/Card/web/PlanCard/List.jsx b/packages/yoga/src/Card/web/PlanCard/List.jsx index 9c94cf22ac..684547f06e 100644 --- a/packages/yoga/src/Card/web/PlanCard/List.jsx +++ b/packages/yoga/src/Card/web/PlanCard/List.jsx @@ -87,27 +87,35 @@ const Button = styled.button` `; const ListItem = withTheme( - ({ text, icon: Icon, buttonProps, theme: yogaTheme, onClick }) => ( - - - {Icon && ( - - {isValidElement(Icon) ? ( - Icon - ) : ( - - )} - + ({ text, icon: Icon, buttonProps, theme: yogaTheme, onClick }) => { + const wrapperProps = onClick + ? { as: 'button', type: 'button', onClick } + : {}; + + return ( + + + {Icon && ( + + {isValidElement(Icon) ? ( + Icon + ) : ( + + )} + + )} + {text} + + {Boolean(Object.keys(buttonProps).length) && ( +