-
-
Notifications
You must be signed in to change notification settings - Fork 112
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
feat: implement highlightedtext component #1864
Changes from all commits
78d54eb
b5272d1
f82687b
341d18b
92080df
1eb1d94
8757dff
45634f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,7 +78,7 @@ | |
min-width: 330px; | ||
} | ||
|
||
.rsg--heading1-6{ | ||
.rsg--heading1-6 { | ||
font-size: 1.2rem; | ||
color: #061C3F; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react'; | ||
import { mount } from 'enzyme'; | ||
import styled from 'styled-components'; | ||
import HighlightedText from '../'; | ||
|
||
describe('<HighlightedText />', () => { | ||
const parts = [ | ||
{ | ||
value: 'Apples', | ||
type: 'text', | ||
}, | ||
{ | ||
value: 'varieties', | ||
type: 'hit', | ||
}, | ||
{ | ||
value: 'Honeycrisp', | ||
type: 'text', | ||
}, | ||
]; | ||
it('should return 3 <span> with theirs respective values because the default wrapper is a span', () => { | ||
const component = mount(<HighlightedText parts={parts} />); | ||
const container = component.find('span'); | ||
expect(container.length).toBe(3); | ||
parts.forEach(({ value }, index) => { | ||
expect( | ||
container | ||
.at(index) | ||
.html() | ||
.includes(value), | ||
).toBe(true); | ||
}); | ||
}); | ||
|
||
it('it should not return a <p> container', () => { | ||
const component = mount(<HighlightedText parts={parts} isInline />); | ||
expect(component.html().includes('<p>')).toBe(false); | ||
}); | ||
|
||
it('should return a custom <span> with id="hitText" in the container at(1) which corresponds to the text that has a type hit', () => { | ||
const TextContainer = styled.span` | ||
color: #808080; | ||
`; | ||
|
||
const HitContainer = styled.span` | ||
color: #fff; | ||
`; | ||
|
||
// eslint-disable-next-line react/prop-types | ||
const HitComponent = ({ children }) => { | ||
return <HitContainer id="hitText">{children}</HitContainer>; | ||
}; | ||
|
||
const component = mount( | ||
<HighlightedText | ||
parts={parts} | ||
textComponent={TextContainer} | ||
hitComponent={HitComponent} | ||
/>, | ||
); | ||
const container = component.find('span'); | ||
expect(container.at(1).prop('id')).toBe('hitText'); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should change these tests to make clearer the difference between a hit and normal text There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this second test you can delete the first the third test all the code |
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react'; | ||
import PropTypes, { bool, node } from 'prop-types'; | ||
|
||
export default function HighlighContainer({ children, isInline, className, style }) { | ||
if (isInline) { | ||
return ( | ||
<span className={className} style={style}> | ||
{children} | ||
</span> | ||
); | ||
} | ||
return ( | ||
<p className={className} style={style}> | ||
{children} | ||
</p> | ||
); | ||
} | ||
|
||
HighlighContainer.propTypes = { | ||
className: PropTypes.string, | ||
style: PropTypes.object, | ||
children: node, | ||
isInline: bool, | ||
}; | ||
|
||
HighlighContainer.defaultProps = { | ||
className: undefined, | ||
style: undefined, | ||
children: undefined, | ||
isInline: false, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
export default function HitText({ | ||
parts, | ||
hitComponent: HitComponent, | ||
textComponent: TextComponent, | ||
}) { | ||
return parts.map((part, index) => { | ||
const key = `part-${index}`; | ||
if (part.type === 'hit') { | ||
return <HitComponent key={key}>{part.value}</HitComponent>; | ||
} | ||
return <TextComponent key={key}>{part.value}</TextComponent>; | ||
}); | ||
} | ||
|
||
HitText.propTypes = { | ||
parts: PropTypes.arrayOf( | ||
PropTypes.exact({ | ||
value: PropTypes.string, | ||
type: PropTypes.string, | ||
}), | ||
), | ||
hitComponent: PropTypes.elementType, | ||
textComponent: PropTypes.elementType, | ||
}; | ||
|
||
HitText.defaultProps = { | ||
parts: undefined, | ||
hitComponent: undefined, | ||
textComponent: undefined, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { ComponentType } from 'react'; | ||
import { BaseProps } from '../types'; | ||
|
||
interface Part { | ||
value?: string; | ||
type?: string; | ||
} | ||
|
||
export interface HighlightedText extends BaseProps { | ||
hitComponent?: ComponentType<{ children?: string }>; | ||
textComponent?: ComponentType<{ children?: string }>; | ||
parts?: Part[]; | ||
isInline?: boolean; | ||
} | ||
|
||
export default function(props: HighlightedText): JSX.Element | null; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import HitText from './hitText'; | ||
import HighlighContainer from './highlighContainer'; | ||
import { DefaultHitContainer, DefaultTextContainer } from './styled/index'; | ||
|
||
LeandroTorresSicilia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** | ||
* HighlightedText is a component that highlights a part of a text. | ||
*/ | ||
|
||
export default function HighlightedText(props) { | ||
const { style, className, parts, hitComponent, textComponent, isInline } = props; | ||
const finalHitContainer = hitComponent || DefaultHitContainer; | ||
const finalTextContainer = textComponent || DefaultTextContainer; | ||
|
||
return ( | ||
<HighlighContainer className={className} style={style} isInline={isInline}> | ||
<HitText | ||
parts={parts} | ||
hitComponent={finalHitContainer} | ||
textComponent={finalTextContainer} | ||
/> | ||
</HighlighContainer> | ||
); | ||
} | ||
|
||
HighlightedText.propTypes = { | ||
/** A CSS class for the outer element, in addition to the component's base classes. */ | ||
className: PropTypes.string, | ||
/** An object with the custom styles of the container. */ | ||
style: PropTypes.object, | ||
/** An array of objects with the text and the part to be highlighted */ | ||
parts: PropTypes.arrayOf( | ||
PropTypes.exact({ | ||
value: PropTypes.string, | ||
type: PropTypes.string, | ||
}), | ||
), | ||
/** | ||
* The component class or function that is going to be use to render | ||
* the highlighted text | ||
*/ | ||
hitComponent: PropTypes.elementType, | ||
/** | ||
* The component class or function that is going to be use to render | ||
* the text not highlighted | ||
*/ | ||
textComponent: PropTypes.elementType, | ||
LeandroTorresSicilia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** A boolean that when it is true display the text inline, and when it is false display the text block. */ | ||
isInline: PropTypes.bool, | ||
}; | ||
|
||
HighlightedText.defaultProps = { | ||
className: undefined, | ||
style: undefined, | ||
parts: undefined, | ||
hitComponent: undefined, | ||
textComponent: undefined, | ||
isInline: false, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# HighlightedText base | ||
##### This example shows the style that is applied by default to the component. | ||
```js | ||
import React from 'react'; | ||
import { HighlightedText } from 'react-rainbow-components'; | ||
|
||
const style = { | ||
maxWidth: '700px', | ||
textAlign: 'center', | ||
padding: '20px', | ||
margin: 'auto', | ||
}; | ||
|
||
const parts = [ | ||
{ | ||
value: 'Apples come in several ', | ||
type: 'text', | ||
}, | ||
{ | ||
value: 'varieties', | ||
type: 'hit', | ||
}, | ||
{ | ||
value: ', including Fuji, Granny Smith, and Honeycrisp.', | ||
type: 'text', | ||
}, | ||
]; | ||
|
||
<HighlightedText parts={parts} style={style} />; | ||
|
||
``` | ||
|
||
# HighlightedText with custom styles | ||
##### This example shows the component when custom styles are applied to it. | ||
|
||
```js | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { HighlightedText } from 'react-rainbow-components'; | ||
|
||
const style = { | ||
maxWidth: '700px', | ||
textAlign: 'center', | ||
padding: '20px', | ||
margin: 'auto', | ||
}; | ||
|
||
const parts = [ | ||
{ | ||
value: 'Apples come in several ', | ||
type: 'text', | ||
}, | ||
{ | ||
value: 'varieties', | ||
type: 'hit', | ||
}, | ||
{ | ||
value: ', including Fuji, Granny Smith, and Honeycrisp.', | ||
type: 'text', | ||
}, | ||
]; | ||
|
||
const TextContainer = styled.span` | ||
color: ${(props) => props.theme.rainbow.palette.text.title}; | ||
font-size: 1rem; | ||
`; | ||
|
||
const HitContainer = styled.span.attrs(props => { | ||
return props.theme.rainbow.palette; | ||
}) | ||
` | ||
background-color: ${(props) => props.brand.main}; | ||
color: ${props => props.getContrastText(props.text.main)}; | ||
font-size: 1rem; | ||
`; | ||
|
||
<HighlightedText parts={parts} style={style} textComponent={TextContainer} hitComponent={HitContainer} />; | ||
|
||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import styled from 'styled-components'; | ||
import attachThemeAttrs from '../../../styles/helpers/attachThemeAttrs'; | ||
|
||
export const DefaultHitContainer = attachThemeAttrs(styled.span)` | ||
LeandroTorresSicilia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
color: ${props => props.palette.text.main}; | ||
font-weight: bold; | ||
font-size: 1rem; | ||
LeandroTorresSicilia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
font-family: 'Lato Black'; | ||
`; | ||
|
||
export const DefaultTextContainer = attachThemeAttrs(styled.span)` | ||
LeandroTorresSicilia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
color: ${props => props.palette.text.main}; | ||
font-size: 1rem; | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HighlightedText.spec.js change to highlightedText.spec.js