Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor ButtonWIthIcon to replace ButtonSearch #81

Merged
merged 12 commits into from
Aug 7, 2018
4 changes: 4 additions & 0 deletions changelogs/react-button-refactor.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
___DESCRIPTION___
change
minor
- (React) Refactored ButtonWithIcon to replace ButtonSearch component #81
18 changes: 0 additions & 18 deletions react/src/components/atoms/buttons/ButtonSearch/ButtonSearch.md

This file was deleted.

This file was deleted.

38 changes: 0 additions & 38 deletions react/src/components/atoms/buttons/ButtonSearch/index.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ export default {
color: {
'': 'grey (default)',
green: 'green'
},
type: {
button: 'button',
submit: 'submit',
reset: 'reset'
}
};
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
### Description
A button that displays with an icon component.
e.g. ButtonSearch, which is used for submitting a keyword search.
e.g. Button with chevron, which is used for toggling between the expanded state and the collapsed state.

### Changes for React
* Button with Icon is a common button pattern that is currently not available in Patternlab. It's an extension on top of the [Button Search atom](https://mayflower.digital.mass.gov/?p=atoms-button-search).
* `classes` array: To improve reusability of this component, classes can now be added to the button by adding them to the new `classes` array.
* `ariaLabel` string: To improve accessibility of this component, an aria-label can be added if the displayed text is not helpful to assistive technologies.
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ storiesOf('atoms/buttons', module)
const props = {
onClick: action('ButtonWithIcon clicked'),
text: text('ButtonWithIcon.text', 'Button With Icon'),
type: select('ButtonWithIcon.type', buttonWithIconOptions.type, 'submit'),
classes: array('ButtonWithIcon.classes', []),
icon: select('ButtonWithIcon.icon', Object.keys(icons), 'chevron'),
iconSize: select('ButtonWithIcon.iconSize', buttonWithIconOptions.size),
iconSize: select('ButtonWithIcon.iconSize', buttonWithIconOptions.size, ''),
iconColor: select('ButtonWithIcon.iconColor', buttonWithIconOptions.color),
canExpand: boolean('ButtonWithIcon.canExpand', true),
expanded: boolean('ButtonWithIcon.expanded', true),
Expand All @@ -37,6 +38,21 @@ storiesOf('atoms/buttons', module)
// Set the icon prop to the actual element based on knob selection.
props.icon = icons[props.icon];

return(
<ButtonWithIcon {...props} />
);
})
)
.add(
'ButtonSearch',
withInfo(`<div>${buttonWithIconReadme}</div>`)(() => {
const props = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you want all these available as knobs for buttonsearch - i would assume search icon etc should not be an option to play with in knobs cause this is a specific variant that needs that icon type

onClick: action('ButtonWithIcon clicked')
};

// Set the icon prop to the actual element based on knob selection.
props.icon = icons[props.icon];

return(
<ButtonWithIcon {...props} />
);
Expand Down
40 changes: 29 additions & 11 deletions react/src/components/atoms/buttons/ButtonWithIcon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,36 @@ class ButtonWithIcon extends React.Component {
}
}
render() {
let classNames = this.props.classes.join(' ');
if (this.props.canExpand) {
const {
classes, canExpand, expanded, capitalized, iconSize, iconColor, icon, type
} = this.props;
let classNames = classes.join(' ');
if (canExpand) {
classNames += ' ma__button-icon--expandable';
classNames += this.props.expanded ? ' ma__button-icon--expanded' : '';
if (expanded) {
classNames += ' ma__button-icon--expanded';
}
}
if (this.props.capitalized) {
if (capitalized) {
classNames += ' ma__button-capitalized';
}
if (this.props.iconSize === 'small') {
if (iconSize === 'small' || icon.type.name === 'SvgChevron') {
classNames += ' ma__icon-small';
}
if (this.props.iconColor === 'green') {
if (iconColor === 'green') {
classNames += ' ma__icon-green';
}
if (icon.type.name === 'SvgSearch') {
classNames += ' ma__button-search';
}
const buttonProps = {
type: 'submit',
type,
className: `ma__button-icon ${classNames}`,
onClick: this.handleClick,
tabIndex: 0
};
return(
<button {...buttonProps} ref={this.setButtonRef}>
<button {...buttonProps} aria-label={this.props.ariaLabel} ref={this.setButtonRef}>
<span>{this.props.text}</span>
{this.props.icon}
</button>
Expand All @@ -57,6 +65,8 @@ ButtonWithIcon.propTypes = {
setButtonRef: PropTypes.func,
// Button text.
text: PropTypes.string,
/** HTML <button> 'type' attribute */
type: PropTypes.oneOf(['submit', 'reset', 'button', '']),
// Button classes.
classes: PropTypes.arrayOf(PropTypes.string),
// Icon to display within the button.
Expand All @@ -67,18 +77,26 @@ ButtonWithIcon.propTypes = {
expanded: PropTypes.bool,
// Adds capitalized class to button if true.
capitalized: PropTypes.bool,
// Defines the size, default size fits the most square icons and "small" setting is specific for the chevron icon.
iconSize: PropTypes.oneOf(['', 'small']),
iconColor: PropTypes.oneOf(['', 'green'])
// Defines the fill color of the svg, default color is $c-gray-dcdcdc.
iconColor: PropTypes.oneOf(['', 'green']),
/** The aria-label property is used to provide the label to any assistive
* technologies. This is useful if the text value is not descriptive of the
* button's functionality. */
ariaLabel: PropTypes.string
};

ButtonWithIcon.defaultProps = {
text: 'Search',
type: 'submit',
classes: [],
icon: <SvgSearch />,
canExpand: false,
capitalized: false,
iconSize: 'small',
iconColor: ''
iconSize: '',
iconColor: '',
ariaLabel: 'search'
};

export default ButtonWithIcon;
7 changes: 4 additions & 3 deletions react/src/components/molecules/HeaderSearch/HeaderSearch.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
display: flex;
position: relative;

.ma__button-icon {
border-right: none;
}

&--responsive {
@media ($bp-medium-max) {
> div:first-child {
Expand All @@ -15,8 +19,5 @@
}
.ma__form {
display: flex;
.ma__button-icon {
border-right: none;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ storiesOf('molecules', module).addDecorator(withKnobs)
const props = {
placeholder: text('HeaderSearch.placeholder', 'Search Mass.gov'),
buttonSearch: {
onClick: (e) => {
action('Button clicked')(e);
e.preventDefault();
},
onClick: action('Button clicked'),
ariaLabel: text('HeaderSearch.buttonSearch.ariaLabel', 'Search'),
text: text('HeaderSearch.buttonSearch.text', 'Search')
},
Expand Down
8 changes: 4 additions & 4 deletions react/src/components/molecules/HeaderSearch/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import ButtonSearch from '../../atoms/buttons/ButtonSearch';
import ButtonWithIcon from '../../atoms/buttons/ButtonWithIcon';
import TypeAheadDropdown from '../../molecules/TypeAheadDropdown';
import './HeaderSearch.css';

Expand Down Expand Up @@ -46,7 +46,7 @@ class HeaderSearch extends React.Component {
type="search"
value={this.state.value}
/>
<ButtonSearch {...headerSearch.buttonSearch} />
<ButtonWithIcon {...headerSearch.buttonSearch} />
</form>
</section>
</div>
Expand All @@ -62,7 +62,7 @@ HeaderSearch.propTypes = {
/** The placeholder text for the input */
placeholder: PropTypes.string,
/** The Search button */
buttonSearch: PropTypes.shape(ButtonSearch.propTypes),
buttonSearch: PropTypes.shape(ButtonWithIcon.propTypes),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prop is no longer being used in render. I don't believe that's intentional?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buttonSearch is accessed on line 49

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to add the props before...

/** Custom submit function */
onSubmit: PropTypes.func,
/** Custom change function for the text input */
Expand All @@ -78,7 +78,7 @@ HeaderSearch.defaultProps = {
label: 'Search terms',
placeholder: 'Search Mass.gov',
buttonSearch: {
ariaLabel: 'Search'
ariaLabel: 'search'
}
};

Expand Down
6 changes: 3 additions & 3 deletions react/src/components/molecules/SearchBannerForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';

import InputText from '../../atoms/forms/InputText';
import ButtonSearch from '../../atoms/buttons/ButtonSearch';
import ButtonWithIcon from '../../atoms/buttons/ButtonWithIcon';

const SearchBannerForm = (searchBannerForm) => {
let { classes = [] } = searchBannerForm.buttonSearch;
Expand All @@ -13,7 +13,7 @@ const SearchBannerForm = (searchBannerForm) => {
<div className="ma__search-banner__input">
<InputText {...searchBannerForm.inputText} />
</div>
<ButtonSearch {...searchBannerForm.buttonSearch} classes={classes} />
<ButtonWithIcon {...searchBannerForm.buttonSearch} classes={classes} />
</form>
);
};
Expand All @@ -26,7 +26,7 @@ SearchBannerForm.propTypes = {
/** The properties for the text input field */
inputText: PropTypes.shape(InputText.propTypes).isRequired,
/** The Search button */
buttonSearch: PropTypes.shape(ButtonSearch.propTypes).isRequired
buttonSearch: PropTypes.shape(ButtonWithIcon.propTypes).isRequired
};

export default SearchBannerForm;
1 change: 0 additions & 1 deletion react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export Placeholder from './components/base/Placeholder'
export Divider from './components/atoms/Divider';
// @atoms/@buttons
export Button from './components/atoms/buttons/Button';
export ButtonSearch from './components/atoms/buttons/ButtonSearch';
export ButtonSort from './components/atoms/buttons/ButtonSort';
export ButtonToggle from './components/atoms/buttons/ButtonToggle';
export ButtonWithIcon from './components/atoms/buttons/ButtonWithIcon';
Expand Down