Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Merge branch 'master' into refactor/editablefield
Browse files Browse the repository at this point in the history
  • Loading branch information
tinkertrain committed May 25, 2021
2 parents deb39e5 + 67e9a5d commit 5365571
Show file tree
Hide file tree
Showing 26 changed files with 650 additions and 245 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "@helpscout/hsds-react",
"version": "3.13.0",
"version": "3.14.0",
"private": false,
"main": "dist/index.js",
"module": "dist/index.es.js",
Expand Down
32 changes: 29 additions & 3 deletions src/components/Attachment/Attachment.css.js
Expand Up @@ -73,6 +73,11 @@ export const AttachmentUI = styled.a`
${d400Effect}
}
&:focus {
outline: none;
box-shadow: 0 0 0 2px ${getColor('blue.500')};
}
&.has-image {
padding: 3px;
}
Expand Down Expand Up @@ -111,23 +116,44 @@ export const AttachmentUI = styled.a`
${bem.element('closeButton')} {
${cardStyles()};
display: block;
clip: rect(0, 0, 0, 0);
border-radius: 9999px !important;
position: absolute;
right: 0;
top: 0;
transform: translate(50%, -50%);
z-index: 1;
opacity: 0;
transition: all 200ms linear;
will-change: box-shadow, color, opacity;
box-shadow: inset 0 0 0 1px ${getColor('grey.700')};
color: ${getColor('charcoal.300')};
& .c-Icon {
&,
&:focus,
&:hover {
opacity: 1;
}
}
}
&:hover,
&:focus {
${bem.element('closeButton')} {
clip: unset;
opacity: 1;
}
}
${bem.element('closeButton')}:focus {
clip: unset;
opacity: 1;
box-shadow: 0 0 0 2px ${getColor('blue.500')};
}
${bem.element('closeButton')}:hover {
box-shadow: inset 0 0 0 1px ${getColor('red.500')};
color: ${getColor('red.500')};
}
`
17 changes: 17 additions & 0 deletions src/components/Attachment/Attachment.stories.mdx
Expand Up @@ -98,3 +98,20 @@ A Provider component provides child components with props accessible as `context
</Attachment.Provider>
</Story>
</Canvas>

#### Preview theme with image

<Canvas>
<Story name="Preview theme with image">
<div style={{ width: '86px' }}>
<Attachment.Provider theme="preview">
<Attachment
name={text('name', 'image.png')}
imageUrl={
'http://matthewjamestaylor.com/img/illustrations/large/how-to-convert-a-liquid-layout-to-fixed-width.jpg'
}
/>
</Attachment.Provider>
</div>
</Story>
</Canvas>
24 changes: 12 additions & 12 deletions src/components/Avatar/Avatar.Image.jsx
Expand Up @@ -10,7 +10,7 @@ import getValidProps from '@helpscout/react-utils/dist/getValidProps'
import VisuallyHidden from '../VisuallyHidden'
import { classNames } from '../../utilities/classNames'
import { noop } from '../../utilities/other'
import { ImageWrapperUI, ImageUI, TitleUI } from './Avatar.css'
import { ImageWrapperUI, ImageUI, InitialsUI } from './Avatar.css'
import { getAnimationProps } from './Avatar.utils'

let cache = {}
Expand Down Expand Up @@ -184,15 +184,15 @@ export class AvatarImage extends React.PureComponent {
}
}

getTitleMarkup() {
const { light, title } = this.props
renderInitials() {
const { light, initials } = this.props

const componentClassName = classNames(
'c-Avatar__title',
'c-Avatar__initials',
light && 'is-light'
)

return <TitleUI className={componentClassName}>{title}</TitleUI>
return <InitialsUI className={componentClassName}>{initials}</InitialsUI>
}

render() {
Expand Down Expand Up @@ -228,7 +228,7 @@ export class AvatarImage extends React.PureComponent {
</ImageUI>
</ImageWrapperUI>
)
return hasImage ? contentMarkup : this.getTitleMarkup()
return hasImage ? contentMarkup : this.renderInitials()
}
}

Expand All @@ -237,12 +237,12 @@ AvatarImage.defaultProps = {
animationDuration: 160,
animationEasing: 'ease',
'data-cy': 'AvatarImage',
src: null,
initials: null,
light: false,
name: null,
onError: noop,
onLoad: noop,
name: null,
title: null,
light: false,
src: null,
}

AvatarImage.propTypes = {
Expand All @@ -251,12 +251,12 @@ AvatarImage.propTypes = {
animationEasing: PropTypes.string,
/** Data attr for Cypress tests. */
'data-cy': PropTypes.string,
src: PropTypes.any,
initials: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
light: PropTypes.bool,
name: PropTypes.string,
onError: PropTypes.func,
onLoad: PropTypes.func,
title: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
src: PropTypes.any,
}

export default AvatarImage
2 changes: 1 addition & 1 deletion src/components/Avatar/Avatar.css.js
Expand Up @@ -155,7 +155,7 @@ export const ImageUI = styled('div')`
width: 100%;
`

export const TitleUI = styled('div')`
export const InitialsUI = styled('div')`
color: white;
line-height: 1;
text-transform: uppercase;
Expand Down
8 changes: 4 additions & 4 deletions src/components/Avatar/Avatar.jsx
Expand Up @@ -114,7 +114,7 @@ export class Avatar extends React.PureComponent {

const hasImage = this.src.length > 0 && !this.state.imageFailed

const title = this.getTitle()
const initials = this.getInitials()
return (
<AvatarCrop
className={shapeClassnames}
Expand All @@ -129,7 +129,7 @@ export class Avatar extends React.PureComponent {
className={classNames('c-Avatar__imageMainWrapper', shapeClassnames)}
src={this.src}
name={name}
title={title}
initials={initials}
light={light}
onError={this.onImageLoadedError}
onLoad={this.onImageLoadedSuccess}
Expand All @@ -143,7 +143,7 @@ export class Avatar extends React.PureComponent {
)}
src={fallbackImage}
name={name}
title={title}
initials={initials}
light={light}
/>
)}
Expand Down Expand Up @@ -182,7 +182,7 @@ export class Avatar extends React.PureComponent {
)
}

getTitle() {
getInitials() {
const { count, initials, name } = this.props

return count || initials || nameToInitials(name)
Expand Down
2 changes: 1 addition & 1 deletion src/components/Avatar/Avatar.test.js
Expand Up @@ -16,7 +16,7 @@ const ui = {
borderAnimation: '.c-Avatar__borderAnimation',
image: '.c-Avatar__image',
imageWrapper: '.c-Avatar__imageWrapper',
initials: '.c-Avatar__title',
initials: '.c-Avatar__initials',
action: '.c-Avatar__action',
}

Expand Down
23 changes: 23 additions & 0 deletions src/components/DropList/DropList.stories.mdx
Expand Up @@ -711,6 +711,29 @@ The `toggler` prop accepts any React component, so you can provide your own cust
/>
</div>
</Story>
<Story name="Toggler: SelectTag with error">
<div
style={{
width: '400px',
margin: '50px 100px 0 150px',
border: '1px dashed silver',
borderRadius: '5px',
padding: '20px',
}}
>
<DropList
items={regularItems}
toggler={
<SelectTag
onClick={() => {
console.log('Clicked from story')
}}
error={'Some error'}
/>
}
/>
</div>
</Story>
<Story name="Toggler: SplittedButton">
<div
style={{
Expand Down
27 changes: 26 additions & 1 deletion src/components/DropList/DropList.test.js
@@ -1,5 +1,5 @@
import React from 'react'
import { render, waitFor } from '@testing-library/react'
import { getByLabelText, render, waitFor } from '@testing-library/react'
import user from '@testing-library/user-event'
import { css } from 'styled-components'
import DropList from './DropList'
Expand Down Expand Up @@ -628,6 +628,31 @@ describe('Togglers', () => {
})
})

describe('SelectTag error state', () => {
test('Should show error when error provided to toggler', async () => {
const error = 'Some error'
const { getByLabelText, getByTitle } = render(
<DropList items={beatles} toggler={<SelectTag error={error} />} />
)

await waitFor(() => {
expect(getByTitle('alert')).toBeInTheDocument()
})
expect(getByLabelText('toggle menu')).toHaveClass('is-error')
})

test('Should not show error when none', async () => {
const { getByLabelText, queryByTitle } = render(
<DropList items={beatles} toggler={<SelectTag />} />
)

await waitFor(() => {
expect(getByLabelText('toggle menu')).not.toHaveClass('is-error')
})
expect(queryByTitle('alert')).not.toBeInTheDocument()
})
})

test('Should run action click callback on a SplittedButton', async () => {
const onActionClick = jest.fn()
const { getByText } = render(
Expand Down
41 changes: 39 additions & 2 deletions src/components/DropList/DropList.togglers.jsx
Expand Up @@ -6,6 +6,8 @@ import { noop } from '../../utilities/other'
import ControlGroup from '../ControlGroup'
import HSDSButton from '../Button'
import Icon from '../Icon'
import { STATES } from '../../constants'
import Tooltip from '../Tooltip'

export const SimpleButton = forwardRef(
(
Expand Down Expand Up @@ -196,14 +198,33 @@ const SplitButtonTogglerUI = styled(HSDSButton)`
}
`

const ErrorTooltipIcon = ({ error }) => {
return (
<Tooltip
animationDelay={0}
animationDuration={0}
closeOnContentClick={true}
display="block"
placement="top-end"
title={error}
>
<Icon name={'alert'} size={24} state={STATES.error} tabIndex={-1} />
</Tooltip>
)
}

export const SelectTag = forwardRef(
({ isActive = false, text = '', onClick = noop, ...rest }, ref) => {
({ isActive = false, text = '', onClick = noop, error, ...rest }, ref) => {
const className = classNames(
'DropListToggler SelectTagToggler',
error && 'is-error'
)
return (
<SelectUI
aria-label="toggle menu"
aria-haspopup="true"
aria-expanded={isActive}
className="DropListToggler SelectTagToggler"
className={className}
data-cy="DropList.SelectTagToggler"
data-testid="DropList.SelectTagToggler"
onClick={onClick}
Expand All @@ -213,6 +234,12 @@ export const SelectTag = forwardRef(
>
<span>{text}</span>
<SelectArrowsUI />
{error && (
// avoid list open/close when clicked on error icon
<SelectErrorTooltipIconUI onClick={e => e.stopPropagation()}>
<ErrorTooltipIcon error={error} />
</SelectErrorTooltipIconUI>
)}
</SelectUI>
)
}
Expand All @@ -235,13 +262,19 @@ const SelectUI = styled('button')`
font-size: 13px;
color: ${getColor('charcoal.600')};
&.is-error {
box-shadow: inset 0 0 0 2px ${getColor('red.500')};
padding-right: 10px;
}
&:focus {
outline: 0;
box-shadow: inset 0 0 0 2px ${getColor('blue.500')};
}
`

const SelectArrowsUI = styled('div')`
margin-left: auto;
width: 7px;
height: 14px;
position: relative;
Expand All @@ -266,6 +299,10 @@ const SelectArrowsUI = styled('div')`
}
`

const SelectErrorTooltipIconUI = styled('div')`
margin-left: 8px;
`

const KebabUI = styled('button')`
width: 24px;
height: 24px;
Expand Down
5 changes: 3 additions & 2 deletions src/components/Emoticon/Emoticon.css.js
@@ -1,10 +1,11 @@
import styled from 'styled-components'
import { getColor } from '../../styles/utilities/color'

// Note: colours here are not from the Help Scout palette
// Note: some colours here are not from the Help Scout palette
export const reactionEmoticonsColours = {
off: {
head: '#E5E9EC',
face: '#A5B2BD',
face: getColor('charcoal.300'),
},
on: {
face: '#2E2D2E',
Expand Down

0 comments on commit 5365571

Please sign in to comment.