mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 18:23:32 -05:00
Merge pull request #3210 from overleaf/ta-icon-component
Create Icon Component in React GitOrigin-RevId: 34161b3afa2c00dbca2423b1e5a42b29846fa6e4
This commit is contained in:
parent
739b301419
commit
d87ad11719
4 changed files with 92 additions and 12 deletions
|
@ -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
|
||||
|
|
|
@ -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}>
|
||||
|
|
36
services/web/frontend/js/shared/components/icon.js
Normal file
36
services/web/frontend/js/shared/components/icon.js
Normal 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
|
46
services/web/test/frontend/shared/components/icon.test.js
Normal file
46
services/web/test/frontend/shared/components/icon.test.js
Normal 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
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue