Merge pull request #3210 from overleaf/ta-icon-component

Create Icon Component in React

GitOrigin-RevId: 34161b3afa2c00dbca2423b1e5a42b29846fa6e4
This commit is contained in:
Jessica Lawshe 2020-09-21 09:14:36 -05:00 committed by Copybot
parent 739b301419
commit d87ad11719
4 changed files with 92 additions and 12 deletions

View file

@ -4,6 +4,7 @@ import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed'
import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
import OutlineList from './outline-list'
import Icon from '../../../shared/components/icon'
function getChildrenLines(children) {
return (children || [])
@ -24,11 +25,6 @@ function OutlineItem({ outlineItem, jumpToLine, highlightedLine }) {
'outline-item-no-children': !outlineItem.children
})
const expandCollapseIconClasses = classNames('fa', 'outline-caret-icon', {
'fa-angle-down': expanded,
'fa-angle-right': !expanded
})
const hasHighlightedChild =
!expanded &&
getChildrenLines(outlineItem.children).includes(highlightedLine)
@ -85,7 +81,10 @@ function OutlineItem({ outlineItem, jumpToLine, highlightedLine }) {
onClick={handleExpandCollapseClick}
aria-label={expanded ? t('collapse') : t('expand')}
>
<i className={expandCollapseIconClasses} />
<Icon
type={expanded ? 'angle-down' : 'angle-right'}
classes={{ icon: 'outline-caret-icon' }}
/>
</button>
) : null}
<button

View file

@ -5,6 +5,7 @@ import classNames from 'classnames'
import { useTranslation, Trans } from 'react-i18next'
import OutlineRoot from './outline-root'
import Icon from '../../../shared/components/icon'
import localStorage from '../../../infrastructure/local-storage'
import withErrorBoundary from '../../../infrastructure/error-boundary'
@ -33,11 +34,6 @@ function OutlinePane({
[isOpen]
)
const expandCollapseIconClasses = classNames('fa', 'outline-caret-icon', {
'fa-angle-down': isOpen,
'fa-angle-right': !isOpen
})
const headerClasses = classNames('outline-pane', {
'outline-pane-disabled': !isTexFile
})
@ -70,7 +66,10 @@ function OutlinePane({
onClick={handleExpandCollapseClick}
aria-label={expanded ? t('hide_outline') : t('show_outline')}
>
<i className={expandCollapseIconClasses} />
<Icon
type={isOpen ? 'angle-down' : 'angle-right'}
classes={{ icon: 'outline-caret-icon' }}
/>
<h4 className="outline-header-name">{t('file_outline')}</h4>
{expanded ? (
<OverlayTrigger placement="top" overlay={tooltip} delayHide={100}>

View file

@ -0,0 +1,36 @@
import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
function Icon({ type, spin, modifier, classes = {}, accessibilityLabel }) {
const iconClassName = classNames(
'fa',
`fa-${type}`,
{
'fa-spin': spin,
[`fa-${modifier}`]: modifier
},
classes.icon
)
return (
<>
<i className={iconClassName} aria-hidden="true" />
{accessibilityLabel ? (
<span className="sr-only">{accessibilityLabel}</span>
) : null}
</>
)
}
Icon.propTypes = {
type: PropTypes.string.isRequired,
spin: PropTypes.bool,
modifier: PropTypes.string,
classes: PropTypes.exact({
icon: PropTypes.string
}),
accessibilityLabel: PropTypes.string
}
export default Icon

View file

@ -0,0 +1,46 @@
import { expect } from 'chai'
import React from 'react'
import { screen, render } from '@testing-library/react'
import Icon from '../../../../frontend/js/shared/components/icon'
describe('<Icon />', function() {
it('renders basic fa classes', function() {
const { container } = render(<Icon type="angle-down" />)
const element = container.querySelector('i.fa.fa-angle-down')
expect(element).to.exist
})
it('renders with aria-hidden', function() {
const { container } = render(<Icon type="angle-down" />)
const element = container.querySelector('i[aria-hidden="true"]')
expect(element).to.exist
})
it('renders accessible label', function() {
render(<Icon type="angle-down" accessibilityLabel="Accessible Foo" />)
screen.getByText('Accessible Foo')
})
it('renders with spin', function() {
const { container } = render(<Icon type="angle-down" spin />)
const element = container.querySelector('i.fa.fa-angle-down.fa-spin')
expect(element).to.exist
})
it('renders with modifier', function() {
const { container } = render(<Icon type="angle-down" modifier="2x" />)
const element = container.querySelector('i.fa.fa-angle-down.fa-2x')
expect(element).to.exist
})
it('renders with custom clases', function() {
const { container } = render(
<Icon type="angle-down" classes={{ icon: 'custom-icon-class' }} />
)
const element = container.querySelector(
'i.fa.fa-angle-down.custom-icon-class'
)
expect(element).to.exist
})
})