Skip to content

Commit

Permalink
feat(link): add button link
Browse files Browse the repository at this point in the history
- make logic and styles from button component reusable
- center align button component, and therefore link button
- add link button to docs
  • Loading branch information
theetrain committed Aug 16, 2017
1 parent 91fc31c commit d8c2645
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 12 deletions.
10 changes: 8 additions & 2 deletions config/styleguide.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ module.exports = {
name = 'ExpandCollapse';
}

// Link component has name-space sub-components
if (path.dirname(componentPath).includes('Link')) {
name = 'Link';
}

return `import { ${name} } from '@telusdigital/tds';`;
},

Expand Down Expand Up @@ -118,7 +123,8 @@ module.exports = {
return [
path.resolve('src/components/Card/Card.jsx'),
path.resolve('src/components/Link/Link.jsx'),
path.resolve('src/components/Link/ChevronLink/ChevronLink.jsx')
path.resolve('src/components/Link/ChevronLink/ChevronLink.jsx'),
path.resolve('src/components/Link/ButtonLink/ButtonLink.jsx')
]
},
sections: [
Expand Down Expand Up @@ -188,7 +194,7 @@ module.exports = {
options: {
modules: true,
localIdentName: 'TDS_[name]__[local]___[hash:base64:5]',
importLoaders: 1, // Number of loaders applied before CSS loader
importLoaders: 1 // Number of loaders applied before CSS loader
}
},
'sass-loader'
Expand Down
4 changes: 2 additions & 2 deletions src/components/Button/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import safeRest from '../../safeRest';

import styles from './Button.modules.scss';

const getClassName = (variant, invert) => {
export const getClassName = (variant, invert) => {
if (variant === 'primary' && invert) {
warn('Button', 'Primary buttons cannot be inverted.');

Expand All @@ -20,7 +20,7 @@ const getClassName = (variant, invert) => {
return styles[variant];
};

const preventDisabling = ({ disabled, ...props }) => {
export const preventDisabling = ({ disabled, ...props }) => {
if (disabled) {
warn('Button', 'Buttons are not able to be disabled.');
}
Expand Down
1 change: 1 addition & 0 deletions src/components/Button/Button.modules.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ $text-color: $color-white;

font-family: $font-telus;
font-size: 1rem;
text-align: center;

cursor: pointer;
}
Expand Down
41 changes: 41 additions & 0 deletions src/components/Link/ButtonLink/ButtonLink.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Link as ReactRouterLink } from 'react-router-dom';

import safeRest from '../../../safeRest';
import { getClassName, preventDisabling } from '../../Button/Button';

import styles from '../../Button/Button.modules.scss';

/**
* <span class="docs--badge green">new!</span> <span class="docs--badge purple">v0.21.0</span>
*/
const ButtonLink = ({ variant, invert, children, ...rest }) => {
const restNoDisabled = preventDisabling(rest);

return React.createElement(
rest.to ? ReactRouterLink : 'a',
{
...safeRest(restNoDisabled),
className: getClassName(variant, invert)
},
children
);
};
ButtonLink.propTypes = {
variant: PropTypes.oneOf([
'primary',
'secondary',
'outlined'
]),
invert: PropTypes.bool,
children: PropTypes.string.isRequired
};
ButtonLink.defaultProps = {
variant: 'primary',
invert: false
};
ButtonLink.displayName = 'Link.Button';

export default ButtonLink;
27 changes: 27 additions & 0 deletions src/components/Link/ButtonLink/ButtonLink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### Minimal Usage

```
<Link.Button>Find out how</Link.Button>
```

### Variants

```
const PurpleBlock = require('../../__docs__/PurpleBlock').default;
<div>
<Link.Button variant="primary">Explore</Link.Button>
<Link.Button variant="secondary">Take me there</Link.Button>
<br/>
<br/>
<PurpleBlock>
<Link.Button variant="outlined">Find me</Link.Button>
</PurpleBlock>
</div>
```

### Inverted Button Links

```
<Link.Button invert>Learn more</Link.Button>
```
87 changes: 87 additions & 0 deletions src/components/Link/ButtonLink/__tests__/ButtonLink.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { shallow } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';

import { warn } from '../../../../warn';

import Link from '../../Link';

jest.mock('../../../../warn', () => (
{ warn: jest.fn() }
));

describe('Link.Button', () => {
const doShallow = (overrides = {}) => shallow(
<Link.Button {...overrides}>Go home</Link.Button>
);
const doShallowWithRouter = (overrides = {}) => shallow(
<MemoryRouter>
<Link.Button {...overrides}>Go home</Link.Button>
</MemoryRouter>
);

it('is an anchor HTML element when using the href attribute', () => {
const link = doShallow({ href: 'http://telus.com' });

expect(link).toHaveTagName('a');
expect(link).toHaveProp('href', 'http://telus.com');
});

it('is a React Router Link when using the to attribute', () => {
const link = doShallowWithRouter({ to: '/about' });

const reactRouterLink = link.find('Router').dive().dive();
expect(reactRouterLink).toMatchSelector('Link');
expect(reactRouterLink).toHaveProp('to', '/about');
});

it('can be presented as one of the allowed variants', () => {
let button = doShallow();
expect(button).toHaveClassName('primary');

button = doShallow({ variant: 'primary' });
expect(button).toHaveClassName('primary');

button = doShallow({ variant: 'secondary' });
expect(button).toHaveClassName('secondary');

button = doShallow({ variant: 'outlined' });
expect(button).toHaveClassName('outlined');
});

it('can be inverted for secondary and outlined variants', () => {
const secondaryButton = doShallow({ variant: 'secondary', invert: true });
expect(secondaryButton).toHaveClassName('secondaryInverted');

const outlinedButton = doShallow({ variant: 'outlined', invert: true });
expect(outlinedButton).toHaveClassName('outlinedInverted');
});

it('can not be inverted for primary variant', () => {
const button = doShallow({ variant: 'primary', invert: true });

expect(button).toHaveClassName('primary');
expect(warn).toHaveBeenCalled();
});

it('can not be disabled', () => {
const button = doShallow({ disabled: true });

expect(button).not.toHaveProp('disabled');
expect(warn).toHaveBeenCalled();
});

it('passes additional attributes to button element', () => {
const button = doShallow({ id: 'the-button', tabindex: 1 });

expect(button).toHaveProp('id', 'the-button');
expect(button).toHaveProp('tabindex', 1);
});

it('does not allow custom CSS', () => {
const button = doShallow({ className: 'my-custom-class', style: { color: 'hotpink' } });

expect(button).not.toHaveProp('className', 'my-custom-class');
expect(button).not.toHaveProp('style');
});
})
3 changes: 3 additions & 0 deletions src/components/Link/ChevronLink/ChevronLink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const getIcon = (glyph, className) => (
</span>
);

/**
* <span class="docs--badge green">new!</span> <span class="docs--badge purple">v0.21.0</span>
*/
const ChevronLink = ({ variant, direction, children, ...rest }) => (
React.createElement(
rest.to ? ReactRouterLink : 'a',
Expand Down
13 changes: 5 additions & 8 deletions src/components/Link/ChevronLink/ChevronLink.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
### Minimal Usage

```
<Link.Chevron href="https://telus.com">Go to Telus.com</Link.Chevron>
<Link.Chevron href="">Go to Telus.com</Link.Chevron>
```

### Colours
Expand All @@ -11,24 +11,21 @@ const PurpleBlock = require('../../__docs__/PurpleBlock').default;
<div>
<div>
<Link.Chevron href="https://telus.com" variant="primary">See latest devices</Link.Chevron>
<Link.Chevron href="" variant="primary">See latest devices</Link.Chevron>
</div>
<div>
<Link.Chevron href="https://telus.com" variant="secondary">Get great deals</Link.Chevron>
<Link.Chevron href="" variant="secondary">Get great deals</Link.Chevron>
</div>
<PurpleBlock>
<Link.Chevron href="https://telus.com" variant="inverted">Find out how</Link.Chevron>
<Link.Chevron href="" variant="inverted">Find out how</Link.Chevron>
</PurpleBlock>
</div>
```

```
```

### Left-facing chevron

```
<Link.Chevron href="https://telus.com" direction="left">Plans</Link.Chevron>
<Link.Chevron href="" direction="left">Plans</Link.Chevron>
```
5 changes: 5 additions & 0 deletions src/components/Link/Link.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import PropTypes from 'prop-types';
import { Link as ReactRouterLink } from 'react-router-dom';

import ChevronLink from './ChevronLink/ChevronLink';
import ButtonLink from './ButtonLink/ButtonLink';
import safeRest from '../../safeRest';

import styles from './Link.modules.scss';

const getClassName = invert => (invert ? styles.inverted : styles.base);

/**
* <span class="docs--badge green">new!</span> <span class="docs--badge purple">v0.21.0</span>
*/
const Link = ({ invert, children, ...rest }) => (
React.createElement(
rest.to ? ReactRouterLink : 'a',
Expand All @@ -33,5 +37,6 @@ Link.defaultProps = {
};

Link.Chevron = ChevronLink;
Link.Button = ButtonLink;

export default Link;

0 comments on commit d8c2645

Please sign in to comment.