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

feat: implement highlightedtext component #1864

Merged
merged 8 commits into from
Oct 5, 2020
5 changes: 5 additions & 0 deletions library/styleguideComponents/ReactComponent/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,8 @@
margin: 40px 20px 0 0;
min-width: 330px;
}

.rsg--heading1-6 {
font-size: 1.2rem;
color: #061C3F;
}
104 changes: 104 additions & 0 deletions src/components/HighlightedText/__test__/HighlightedText.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
Copy link
Contributor

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

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
.at(0)
.html()
.includes('Apples'),
).toBe(true);
expect(
container
.at(1)
.html()
.includes('varieties'),
).toBe(true);
expect(
container
.at(2)
.html()
.includes('Honeycrisp'),
).toBe(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be cleaner like this

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('should return 3 custom <span> with theirs respective values because the custom wrapper is a span', () => {
const TextContainer = styled.span`
color: grey;
`;

const HitContainer = styled.span`
color: #fff;
`;

const component = mount(
<HighlightedText
parts={parts}
textComponent={TextContainer}
hitComponent={HitContainer}
/>,
);
const container = component.find('span');
expect(
container
.at(0)
.html()
.includes('Apples'),
).toBe(true);
expect(
container
.at(1)
.html()
.includes('varieties'),
).toBe(true);
expect(
container
.at(2)
.html()
.includes('Honeycrisp'),
).toBe(true);
});

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

The 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


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: grey;
`;

const HitContainer = styled.span`
color: #fff;
`;

// eslint-disable-next-line react/prop-types
const hitComponent = ({ children }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

capitalize the first letter HitComponent

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');
});
});
33 changes: 33 additions & 0 deletions src/components/HighlightedText/hitText.js
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,
};
15 changes: 15 additions & 0 deletions src/components/HighlightedText/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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 }>;
part?: Part[];

Choose a reason for hiding this comment

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

it is parts:
parts?: Part[];

}

export default function(props: HighlightedText): JSX.Element | null;
58 changes: 58 additions & 0 deletions src/components/HighlightedText/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import HitText from './hitText';
import { DefaultHitContainer, DefaultTextContainer } from './styled/index';

/**
* HighlightedText is a component that highlights a part of a text.
*/

LeandroTorresSicilia marked this conversation as resolved.
Show resolved Hide resolved
function HighlightedText(props) {

Choose a reason for hiding this comment

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

when using function declaration you can export directly here like:
export default function HighlightedText(props) {...

const { style, className, parts, hitComponent, textComponent } = props;
const finalHitContainer = hitComponent || DefaultHitContainer;
const finalTextContainer = textComponent || DefaultTextContainer;

return (
<p className={className} style={style}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need to add a new prop isInline in order to change the p element by a span element, also we should add a useful description for this prop

Copy link
Collaborator

Choose a reason for hiding this comment

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

add a new example using the isInline prop

<HitText
parts={parts}
hitComponent={finalHitContainer}
textComponent={finalTextContainer}
/>
</p>
);
}

export default HighlightedText;

HighlightedText.propTypes = {
/** The class of the component. */
Copy link
Collaborator

Choose a reason for hiding this comment

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

In order to be consistent, we should use the same description that we use in other components
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
};

HighlightedText.defaultProps = {
className: undefined,
style: undefined,
parts: undefined,
hitComponent: undefined,
textComponent: undefined,
};
77 changes: 77 additions & 0 deletions src/components/HighlightedText/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# HighlightedText base
##### This example shows the style that is applied by default to the component.
```js
import React, { useState } from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

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

useState is not used in the example

import { HighlightedText } from 'react-rainbow-components';
Copy link
Contributor

Choose a reason for hiding this comment

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

identation


const style = {
maxWidth:"700px",
textAlign:"center",
padding:"20px",
margin:"auto",
LeandroTorresSicilia marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

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

use single quotes and add a space after the : symbol like:
maxWidth: '700px',

};

const parts = [
{
"value" : "Apples come in several ",
"type" : "text"
},
{
"value" : "varieties",
"type" : "hit"
},
{
"value" : ", including Fuji, Granny Smith, and Honeycrisp.",
"type" : "text"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation

];

<HighlightedText parts={parts} style={style} />

```

# HighlightedText with custom styles
##### This example shows the component when custom styles are applied to it.

```js
import React, { useState } from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

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

same before

import styled from 'styled-components';
import { HighlightedText } from 'react-rainbow-components';
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation


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"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation

];

const TextContainer = styled.span`
color: gray;
font-size: 1rem;
`;

const HitContainer = styled.span`
background-color: #00a3dc;
color: #fff;
font-size: 1rem;
`;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be better to use the theme colors for this example


<HighlightedText parts={parts} style={style} textComponent={TextContainer} hitComponent={HitContainer}/>

```

14 changes: 14 additions & 0 deletions src/components/HighlightedText/styled/index.js
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;
`;
1 change: 1 addition & 0 deletions src/components/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export { default as FileSelector } from './FileSelector';
export { default as GMap } from './GMap';
export { default as GoogleAddressLookup } from './GoogleAddressLookup';
export { default as HelpText } from './HelpText';
export { default as HighlightedText } from './HighlightedText';
export { default as ImportRecordsFlow } from './ImportRecordsFlow';
export { default as Input } from './Input';
export { default as Lookup } from './Lookup';
Expand Down
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export { default as FileSelector } from './FileSelector';
export { default as GMap } from './GMap';
export { default as GoogleAddressLookup } from './GoogleAddressLookup';
export { default as HelpText } from './HelpText';
export { default as HighlightedText } from './HighlightedText';
yvmunayev marked this conversation as resolved.
Show resolved Hide resolved
export { default as ImportRecordsFlow } from './ImportRecordsFlow';
export { default as Input } from './Input';
export { default as Lookup } from './Lookup';
Expand Down