@dennisdigital/polaris-components-link
Advanced tools
Comparing version 1.6.2 to 2.0.0-alpha.0
import React from 'react'; | ||
import toJson from 'enzyme-to-json'; | ||
import { Route, BrowserRouter as Router } from 'react-router-dom'; | ||
import { Text } from '@dennisdigital/polaris-components-text'; | ||
@@ -9,3 +8,3 @@ import { PolarisApp } from '@dennisdigital/polaris-components-polaris'; | ||
describe('Link', () => { | ||
describe('Molecule: Link', () => { | ||
global.window = Object.create(window); | ||
@@ -19,12 +18,8 @@ Object.defineProperty(window, 'location', { | ||
/** | ||
* Checks whether the Link renders without any props | ||
* Checks whether the Link renders no props are passed | ||
*/ | ||
it('should render without any props', () => { | ||
const component = mount( | ||
<Router> | ||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} | ||
<Route exact path="/" render={() => <Link />} /> | ||
</Router>, | ||
); | ||
expect(toJson(component)).toMatchSnapshot(); | ||
it('shouldnt render component without any props', () => { | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
const component = mount(<Link />); | ||
expect((component).contains('<Link />')).toBe(false); | ||
}); | ||
@@ -36,7 +31,3 @@ | ||
it('should render without any optional props', () => { | ||
const component = mount( | ||
<Router> | ||
<Route exact path="/" render={() => <Link href="/test" />} /> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="/test" />); | ||
expect(toJson(component)).toMatchSnapshot(); | ||
@@ -46,10 +37,33 @@ }); | ||
/** | ||
* Checks whether the Link renders if only id is passed | ||
*/ | ||
it('should render if only id is passed', () => { | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
const component = mount(<Link id="main" />); | ||
expect(toJson(component)).toMatchSnapshot(); | ||
}); | ||
/** | ||
* Checks whether the Link renders if only name is passed | ||
*/ | ||
it('should render if only name is passed', () => { | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
const component = mount(<Link name="anchor-block" />); | ||
expect(toJson(component)).toMatchSnapshot(); | ||
}); | ||
/** | ||
* Checks whether the Link renders if only href is # | ||
*/ | ||
it('should render if only href # is passed', () => { | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
const component = mount(<Link href="#" />); | ||
expect(toJson(component)).toMatchSnapshot(); | ||
}); | ||
/** | ||
* Checks the href props | ||
*/ | ||
it('checks href props', () => { | ||
const component = mount( | ||
<Router> | ||
<Route exact path="/" render={() => <Link href="/test" />} /> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="/test" />); | ||
expect(component.find('a').prop('href')).toEqual('/test'); | ||
@@ -62,7 +76,3 @@ }); | ||
it('checks href props type', () => { | ||
const component = mount( | ||
<Router> | ||
<Route exact path="/" render={() => <Link href="/test" />} /> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="/test" />); | ||
expect(typeof component.find('a').prop('href')).toEqual('string'); | ||
@@ -76,9 +86,5 @@ }); | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="/test"><Text /></Link>} | ||
/> | ||
</Router>, | ||
<Link href="/test"> | ||
<Text /> | ||
</Link>, | ||
); | ||
@@ -94,14 +100,6 @@ | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link href="/test"> | ||
<Text content="some text" /> | ||
<Text content="some other text" /> | ||
</Link> | ||
)} | ||
/> | ||
</Router>, | ||
<Link href="/test"> | ||
<Text content="some text" /> | ||
<Text content="some other text" /> | ||
</Link>, | ||
); | ||
@@ -117,13 +115,20 @@ | ||
it('checks that children can be different types', () => { | ||
const component = mount(<Link href="/test">Some random text</Link>); | ||
expect(component.find('a').text()).toEqual('Some random text'); | ||
}); | ||
/** | ||
* Checks if the component without href will return children | ||
*/ | ||
it('checks if the component without href will return children', () => { | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="/test">Some random text</Link>} | ||
/> | ||
</Router>, | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
<Link> | ||
<Text content="This is text" /> | ||
</Link>, | ||
); | ||
expect(component.find('a').text()).toEqual('Some random text'); | ||
expect(component.find('Text span').text()).toEqual('This is text'); | ||
}); | ||
@@ -136,11 +141,3 @@ | ||
const onClickFunction = jest.fn(); | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="test" onClick={onClickFunction} />} | ||
/> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="test" onClick={onClickFunction} />); | ||
@@ -155,24 +152,15 @@ component.find('a').simulate('click'); | ||
*/ | ||
it('should render custom LinkComponent', () => { | ||
// eslint-disable-next-line react/prop-types | ||
const CustomLink = ({ to, children }) => <span to={to}>{children}</span>; | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<PolarisApp config={{ LinkComponent: CustomLink }}> | ||
<Link href="test"> | ||
Custom Link | ||
</Link> | ||
</PolarisApp> | ||
)} | ||
/> | ||
</Router>, | ||
); | ||
// @TODO check if LinkComponent is in use in any of the polaris project (except evo) | ||
// it('should render custom LinkComponent', () => { | ||
// // eslint-disable-next-line react/prop-types | ||
// const CustomLink = ({ to, children }) => <span to={to}>{children}</span>; | ||
// const component = mount( | ||
// <PolarisApp config={{ LinkComponent: CustomLink }}> | ||
// <Link href="test">Custom Link</Link> | ||
// </PolarisApp>, | ||
// ); | ||
// | ||
// expect(component.find('span').text()).toEqual('Custom Link'); | ||
// }); | ||
expect(component.find('span').text()).toEqual('Custom Link'); | ||
}); | ||
/** | ||
@@ -183,14 +171,6 @@ * Checks the extraClassNames props | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
href="http://test.com" | ||
extraClassNames={{ 'polaris__link--test': true }} | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link | ||
href="http://test.com" | ||
extraClassNames={{ 'polaris__link--test': true }} | ||
/>, | ||
); | ||
@@ -206,9 +186,3 @@ | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="/test" target="_self" rel="bookmark" />} | ||
/> | ||
</Router>, | ||
<Link href="/test" target="_self" rel="bookmark" />, | ||
); | ||
@@ -224,11 +198,3 @@ | ||
it('checks the default target prop for external links', () => { | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="http://test.com" />} | ||
/> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="http://test.com" />); | ||
@@ -243,11 +209,3 @@ expect(component.find('a').prop('target')).toEqual('_blank'); | ||
it('checks if the external link will get default rel', () => { | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="http://test.com" />} | ||
/> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="http://test.com" />); | ||
@@ -263,15 +221,3 @@ expect(component.find('a').prop('target')).toEqual('_blank'); | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
href="http://test.com" | ||
target="_self" | ||
rel="nofollow" | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link href="http://test.com" target="_self" rel="nofollow" />, | ||
); | ||
@@ -287,11 +233,3 @@ | ||
it('recognises absolute internal urls', () => { | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="https://www.example.com/test" />} | ||
/> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="https://www.example.com/test" />); | ||
@@ -305,11 +243,3 @@ expect(toJson(component)).toMatchSnapshot(); | ||
it('pass the URL query strings and hash from relative links', () => { | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => <Link href="/test?query-string=value#hash" />} | ||
/> | ||
</Router>, | ||
); | ||
const component = mount(<Link href="/test?query-string=value#hash" />); | ||
@@ -324,13 +254,3 @@ expect(toJson(component)).toMatchSnapshot(); | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
href="https://www.example.com/test?query-string=value#hash" | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link href="https://www.example.com/test?query-string=value#hash" />, | ||
); | ||
@@ -346,13 +266,3 @@ | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
href="https://www.differenthost.com/test?query-string=value#hash" | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link href="https://www.differenthost.com/test?query-string=value#hash" />, | ||
); | ||
@@ -369,13 +279,3 @@ | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
href="https://my.www.example.com/test?query-string=value#hash" | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link href="https://my.www.example.com/test?query-string=value#hash" />, | ||
); | ||
@@ -391,16 +291,8 @@ | ||
const component = mount( | ||
<Router> | ||
<Route | ||
exact | ||
path="/" | ||
render={() => ( | ||
<Link | ||
ariaLabel="Link aria-label" | ||
href="/test" | ||
screenReaderText="Screen Reader Text" | ||
title="Link title" | ||
/> | ||
)} | ||
/> | ||
</Router>, | ||
<Link | ||
ariaLabel="Link aria-label" | ||
href="/test" | ||
screenReaderText="Screen Reader Text" | ||
title="Link title" | ||
/>, | ||
); | ||
@@ -410,12 +302,12 @@ | ||
expect(component.find('a').prop('title')).toEqual('Link title'); | ||
expect(component.find('a span.screen-reader-text').text()).toEqual('Screen Reader Text'); | ||
expect(component.find('a span.screen-reader-text').text()).toEqual( | ||
'Screen Reader Text', | ||
); | ||
}); | ||
}); | ||
describe('Link AMP: Renders Link correctly', () => { | ||
describe('Molecule: Link AMP: Renders Link correctly', () => { | ||
const AmpElement = ( | ||
<PolarisApp config={{ platform: 'amp' }}> | ||
<Router> | ||
<Link href="/test">Link</Link> | ||
</Router> | ||
<Link href="/test">Link</Link> | ||
</PolarisApp> | ||
@@ -422,0 +314,0 @@ ); |
210
Link.js
@@ -8,4 +8,2 @@ /** | ||
import PropTypes from 'prop-types'; | ||
import { Link as RouterLink } from 'react-router-dom'; | ||
import { HashLink } from 'react-router-hash-link'; | ||
import classNames from 'classnames'; | ||
@@ -61,3 +59,3 @@ import { withPolaris } from '@dennisdigital/polaris-components-polaris'; | ||
|| href.startsWith('#') | ||
|| (!ssr && (parseUrl(href).hostname === window.location.hostname))) { | ||
|| (!ssr && parseUrl(href).hostname === window.location.hostname)) { | ||
return true; | ||
@@ -94,167 +92,57 @@ } | ||
*/ | ||
const Link = ( | ||
{ | ||
ariaLabel, | ||
children, | ||
context: { | ||
cssPrefix, | ||
LinkComponent, | ||
platform, | ||
}, | ||
extraClassNames, | ||
href, | ||
id, | ||
loadStyles, | ||
name, | ||
onClick, | ||
role, | ||
rel, | ||
screenReaderText, | ||
tabIndex, | ||
target, | ||
title, | ||
const Link = ({ | ||
ariaLabel, | ||
children, | ||
context: { | ||
cssPrefix, | ||
LinkComponent, | ||
}, | ||
) => { | ||
/** | ||
* In case the href is not set, the element could be an anchored block (if | ||
* name or id are provided). Otherwise just return the children block | ||
*/ | ||
if (!href) { | ||
if (name || id) { | ||
extraClassNames, | ||
href, | ||
id, | ||
loadStyles, | ||
name, | ||
onClick, | ||
role, | ||
rel, | ||
screenReaderText, | ||
tabIndex, | ||
target, | ||
title, | ||
}) => { | ||
if (!href && (!id || !name)) { | ||
if (children) { | ||
return ( | ||
// eslint-disable-next-line jsx-a11y/anchor-is-valid | ||
<a | ||
aria-label={ariaLabel} | ||
className={classNames({ | ||
'-is-anchored-block': true, | ||
...extraClassNames, | ||
})} | ||
id={id} | ||
name={name} | ||
rel={rel} | ||
role={role} | ||
target={target} | ||
tabIndex={tabIndex} | ||
title={title} | ||
> | ||
<> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</a> | ||
</> | ||
); | ||
} | ||
return ( | ||
<> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</> | ||
); | ||
return false; | ||
} | ||
// Check if we have a custom LinkComponent which was passed through. | ||
if (LinkComponent) { | ||
return ( | ||
<LinkComponent | ||
aria-label={ariaLabel} | ||
className={classNames({ | ||
'-is-custom-link': true, | ||
...extraClassNames, | ||
})} | ||
role={role} | ||
title={title} | ||
to={href} | ||
> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</LinkComponent> | ||
); | ||
} | ||
// Check if the link internal | ||
const linkIsInternal = isInternal(href); | ||
// if href is not passed, treat link as internal (example: anchor links) | ||
const linkIsInternal = href ? isInternal(href) : true; | ||
if (!linkIsInternal) { | ||
const amp = platform === 'amp'; | ||
const linkTarget = target || '_blank'; | ||
return ( | ||
<a | ||
aria-label={ariaLabel} | ||
className={classNames({ | ||
[`${cssPrefix}__link`]: loadStyles, | ||
'-is-external': !amp, | ||
...extraClassNames, | ||
})} | ||
href={href} | ||
onClick={onClick} | ||
rel={rel || ((linkTarget === '_blank') ? 'noopener' : undefined)} | ||
role={role} | ||
tabIndex={tabIndex} | ||
target={amp ? null : linkTarget} | ||
title={title} | ||
> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</a> | ||
); | ||
} | ||
const linkProps = { | ||
'aria-label': ariaLabel, | ||
className: classNames({ | ||
[`${cssPrefix}__link`]: loadStyles, | ||
...extraClassNames, | ||
}), | ||
id, | ||
name, | ||
onClick, | ||
rel, | ||
role, | ||
tabIndex, | ||
target, | ||
title, | ||
}; | ||
// internal absolute URLs with different subdomains | ||
if ((!ssr && (parseUrl(href).hostname !== window.location.hostname))) { | ||
return ( | ||
<a | ||
{...linkProps} | ||
href={href} | ||
> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</a> | ||
); | ||
} | ||
if (parseUrl(href) && parseUrl(href).hash !== null) { | ||
return ( | ||
<HashLink | ||
{...linkProps} | ||
to={parseUrl(href) || href} | ||
smooth | ||
> | ||
{children} | ||
{screenReaderText && ( | ||
<span className="screen-reader-text">{screenReaderText}</span> | ||
)} | ||
</HashLink> | ||
); | ||
} | ||
return ( | ||
<RouterLink | ||
{...linkProps} | ||
to={parseUrl(href) || href} | ||
<a | ||
aria-label={ariaLabel} | ||
className={classNames({ | ||
[`${cssPrefix}__link`]: loadStyles, | ||
'-is-anchored-block': !href && (name || id), | ||
'-is-custom-link': LinkComponent, | ||
'-is-external': !linkIsInternal, | ||
...extraClassNames, | ||
})} | ||
href={href} | ||
id={id} | ||
name={name} | ||
onClick={onClick} | ||
rel={rel || ((target === '_blank' || !linkIsInternal) ? 'noopener' : undefined)} | ||
role={role} | ||
tabIndex={tabIndex} | ||
target={target || (!linkIsInternal ? '_blank' : null)} | ||
title={title} | ||
> | ||
@@ -265,3 +153,3 @@ {children} | ||
)} | ||
</RouterLink> | ||
</a> | ||
); | ||
@@ -286,3 +174,7 @@ }; | ||
screenReaderText: PropTypes.string, | ||
tabIndex: PropTypes.oneOf([PropTypes.number, PropTypes.bool, PropTypes.string]), | ||
tabIndex: PropTypes.oneOf([ | ||
PropTypes.number, | ||
PropTypes.bool, | ||
PropTypes.string, | ||
]), | ||
target: PropTypes.string, | ||
@@ -289,0 +181,0 @@ title: PropTypes.string, |
65
Link.md
```jsx | ||
import { MemoryRouter as Router } from 'react-router-dom'; | ||
<div> | ||
Internal link | ||
<br /> | ||
<Router> | ||
<Link | ||
href="/test" | ||
target="_blank" | ||
onClick={() => {}} | ||
> | ||
Test link | ||
</Link> | ||
</Router> | ||
<br /> | ||
<br /> | ||
External link | ||
<br /> | ||
<Router> | ||
<Link | ||
href="https://www.google.co.uk" | ||
target="_blank" | ||
> | ||
External test link | ||
</Link> | ||
</Router> | ||
<br /> | ||
<br /> | ||
Internal link with a URL query parameters (<i>?query-param=value</i>) | ||
<br /> | ||
<Router> | ||
<Link href="/test?query-param=value"> | ||
Test link with the query parameter | ||
</Link> | ||
</Router> | ||
<br /> | ||
<br /> | ||
External link with a URL query parameters (<i>?query-param=value</i>) | ||
<br /> | ||
<Router> | ||
Internal link | ||
<br /> | ||
<Link href="/test" target="_blank" onClick={() => {}}> | ||
Test link | ||
</Link> | ||
<br /> | ||
<br /> | ||
External link | ||
<br /> | ||
<Link href="https://www.google.co.uk" target="_blank"> | ||
External test link | ||
</Link> | ||
<br /> | ||
<br /> | ||
Internal link with a URL query parameters (<i>?query-param=value</i>) | ||
<br /> | ||
<Link href="/test?query-param=value">Test link with the query parameter</Link> | ||
<br /> | ||
<br /> | ||
External link with a URL query parameters (<i>?query-param=value</i>) | ||
<br /> | ||
<Link href="https://www.google.co.uk?query-param=value"> | ||
External test link with the query parameter | ||
</Link> | ||
</Router> | ||
External test link with the query parameter | ||
</Link> | ||
</div> | ||
``` |
{ | ||
"name": "@dennisdigital/polaris-components-link", | ||
"version": "1.6.2", | ||
"version": "2.0.0-alpha.0", | ||
"main": "index.js", | ||
@@ -10,5 +10,3 @@ "license": "MIT", | ||
"prop-types": "^15.7.2", | ||
"react": "^16.8.6", | ||
"react-router-dom": "^5.0.1", | ||
"react-router-hash-link": "^1.2.2" | ||
"react": "^16.8.6" | ||
}, | ||
@@ -31,3 +29,3 @@ "devDependencies": { | ||
}, | ||
"gitHead": "f2ac4473156be0943fe974ea3e1904fce498f572" | ||
"gitHead": "656bceadc22431aa69f3d4be4f3d5aaafffc1efc" | ||
} |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
4
24547
438
2
- Removedreact-router-dom@^5.0.1
- Removedreact-router-hash-link@^1.2.2
- Removedhistory@4.10.1(transitive)
- Removedhoist-non-react-statics@3.3.2(transitive)
- Removedisarray@0.0.1(transitive)
- Removedpath-to-regexp@1.9.0(transitive)
- Removedreact-router@5.3.4(transitive)
- Removedreact-router-dom@5.3.4(transitive)
- Removedreact-router-hash-link@1.2.2(transitive)
- Removedresolve-pathname@3.0.0(transitive)
- Removedtiny-invariant@1.3.3(transitive)
- Removedtiny-warning@1.0.3(transitive)
- Removedvalue-equal@1.0.1(transitive)