From 7323f86a702a429af46276c0d5cabc9f71bb60e5 Mon Sep 17 00:00:00 2001 From: ZacharyStair Date: Wed, 20 Feb 2019 18:38:36 -0500 Subject: [PATCH] feat(Button): allows button to render arbitrary component as its root (#1891) * feat(Button): allows button to render arbitrary component as its root leverages a render prop to allow consumers to render whatever they want in place of button or anchor closes #1890 * refactor(Button): consolidates code to choose button node type * fix(Button): fixes props to button and anchor components * refactor(Button): renames render prop to as --- src/components/Button/Button-story.js | 10 +++ src/components/Button/Button-test.js | 17 ++++++ src/components/Button/Button.js | 61 +++++++++++-------- .../__snapshots__/ModalWrapper-test.js.snap | 26 -------- 4 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/components/Button/Button-story.js b/src/components/Button/Button-story.js index 1101df0f32..29473d6809 100644 --- a/src/components/Button/Button-story.js +++ b/src/components/Button/Button-story.js @@ -14,6 +14,7 @@ import AddFilled16 from '@carbon/icons-react/lib/add--filled/16'; import Search16 from '@carbon/icons-react/lib/search/16'; import { settings } from 'carbon-components'; import Button from '../Button'; +import Link from '../Link'; import ButtonSkeleton from '../Button/Button.Skeleton'; import { componentsX } from '../../internal/FeatureFlags'; @@ -80,6 +81,15 @@ storiesOf('Buttons', module) Link   + +   ); }, diff --git a/src/components/Button/Button-test.js b/src/components/Button/Button-test.js index 25c7cb567f..7311eb389e 100644 --- a/src/components/Button/Button-test.js +++ b/src/components/Button/Button-test.js @@ -8,6 +8,7 @@ import React from 'react'; import { iconSearch } from 'carbon-icons'; import Button from '../Button'; +import Link from '../Link'; import ButtonSkeleton from '../Button/Button.Skeleton'; import { shallow, mount } from 'enzyme'; @@ -97,6 +98,22 @@ describe('Button', () => { }); }); + describe('Renders arbitrary component with correct props', () => { + let wrapper; + beforeEach(() => { + wrapper = shallow( + + ); + }); + it('renders as a Link with data attribute', () => { + expect(wrapper.is(Link)).toBe(true); + expect(wrapper.is('[data-foo="foo"]')).toBe(true); + }); + }); + describe('Renders icon buttons', () => { const iconButton = mount( - ); - - const anchor = ( - - {children} - {buttonImage} - + let component = 'button'; + let otherProps = { + disabled, + type, + }; + const anchorProps = { + role: 'button', + href, + }; + if (as) { + component = as; + otherProps = { + ...otherProps, + ...anchorProps, + }; + } else if (href) { + component = 'a'; + otherProps = anchorProps; + } + return React.createElement( + component, + { + ...other, + ...commonProps, + ...otherProps, + }, + children, + buttonImage ); - - return href ? anchor : button; }; Button.propTypes = { @@ -94,6 +101,12 @@ Button.propTypes = { */ children: PropTypes.node, + /** + * Specify how the button itself should be rendered. + * Make sure to apply all props to the root node and render children appropriately + */ + as: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + /** * Specify an optional className to be added to your Button */ diff --git a/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap b/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap index b252c0f26b..08fc27f49a 100644 --- a/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap +++ b/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap @@ -29,7 +29,6 @@ exports[`ModalWrapper should render 1`] = ` Object { "current": , - } - } onClick={[Function]} tabIndex={0} type="button" @@ -201,7 +188,6 @@ exports[`ModalWrapper should render 1`] = ` Object { "current": , - } - } onClick={[Function]} tabIndex={0} type="button"