Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat(alert): add Header and Icon slots #1821

Merged
merged 40 commits into from
Aug 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fca5c3d
add Header and Icon slots in Alert
lucivpav Aug 19, 2019
da379b8
update changelog
lucivpav Aug 19, 2019
ee64ec9
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 19, 2019
89c9c7a
move examples from Variations to Slots
lucivpav Aug 19, 2019
ce38a66
Merge github.com:stardust-ui/react into feat/alert-header-and-icon
lucivpav Aug 19, 2019
1227fbf
Merge branch 'feat/alert-header-and-icon' of github.com:stardust-ui/r…
lucivpav Aug 19, 2019
7cf35a6
extract header styles
lucivpav Aug 19, 2019
9797ea8
header should be shorthand
lucivpav Aug 19, 2019
400bbe7
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 19, 2019
b4b9aff
Merge github.com:stardust-ui/react into feat/alert-header-and-icon
lucivpav Aug 19, 2019
6975e6e
Merge branch 'feat/alert-header-and-icon' of github.com:stardust-ui/r…
lucivpav Aug 19, 2019
881b99e
attempt to resolve circular dep test error
lucivpav Aug 19, 2019
eb6d5e8
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 20, 2019
47bd53e
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 21, 2019
e961e8a
fix a11y
lucivpav Aug 21, 2019
2b49c3a
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 21, 2019
0e9de83
fix build error
lucivpav Aug 21, 2019
0090ed1
fix build error
lucivpav Aug 21, 2019
bc1cffb
rename wrapper to body, fix failing tests
lucivpav Aug 22, 2019
972dc82
add alertProps.ts file
lucivpav Aug 22, 2019
c846213
rename wrapper to body in Alert component
lucivpav Aug 22, 2019
ea76262
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 22, 2019
8b3c1bc
use state instead of prop for the body id
lucivpav Aug 22, 2019
1f374c6
Merge branch 'feat/alert-header-and-icon' of github.com:stardust-ui/r…
lucivpav Aug 22, 2019
6e9510e
use aria-describedby, aria-label
lucivpav Aug 22, 2019
b165c8d
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 22, 2019
ab494b8
replace flex by box
lucivpav Aug 22, 2019
eff83ea
fix failing tests
lucivpav Aug 22, 2019
8048631
improve rtl
lucivpav Aug 22, 2019
b7ada31
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 23, 2019
c7ef52c
minor changes
lucivpav Aug 23, 2019
d39b399
do not use dedicated file for alertProps
lucivpav Aug 23, 2019
47dd275
fix prev commit
lucivpav Aug 23, 2019
93087e1
remove hardcoded aria-label
lucivpav Aug 23, 2019
238fc16
do not use xSpacing prop
lucivpav Aug 23, 2019
e22b228
Merge branch 'master' into feat/alert-header-and-icon
lucivpav Aug 23, 2019
51e90e3
Merge branch 'master' into feat/alert-header-and-icon
layershifter Aug 23, 2019
0696518
header is Text not Box
lucivpav Aug 23, 2019
be3ccdb
Merge branch 'feat/alert-header-and-icon' of github.com:stardust-ui/r…
lucivpav Aug 23, 2019
84f2718
fix prev commit
lucivpav Aug 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Upgrade `FocusTrapZone` to the latest version from `fabric-ui` @sophieH29 ([#1790](https://github.com/stardust-ui/react/pull/1790))
- Add `visible` prop to `Alert` @layershifter ([#1823](https://github.com/stardust-ui/react/pull/1823))
- Add `actions` slot to `Alert` @layershifter ([#1823](https://github.com/stardust-ui/react/pull/1823))
- Add `header` and `icon` slots to `Alert` component @lucivpav ([#1821](https://github.com/stardust-ui/react/pull/1821))

### Documentation
- Restore docs for `Ref` component @layershifter ([#1777](https://github.com/stardust-ui/react/pull/1777))
Expand Down
4 changes: 3 additions & 1 deletion build/gulp/tasks/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ const componentsSrc = [
`${paths.posix.packageSrc('react-component-ref')}/[A-Z]*.tsx`,
`${paths.posix.packageSrc('react')}/lib/accessibility/FocusZone/[A-Z]!(*.types).tsx`,
]
const behaviorSrc = [`${paths.posix.packageSrc('react')}/lib/accessibility/Behaviors/*/[a-z]*.ts`]
const behaviorSrc = [
`${paths.posix.packageSrc('react')}/lib/accessibility/Behaviors/*/[a-z]*Behavior.ts`,
]
const examplesIndexSrc = `${paths.posix.docsSrc()}/examples/*/*/*/index.tsx`
const examplesSrc = `${paths.posix.docsSrc()}/examples/*/*/*/!(*index|.knobs).tsx`
const markdownSrc = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleHeader = () => (
<Alert header="Action required" content="Please set a new password" />
)

export default AlertExampleHeader
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleHeader = () => (
<Alert header="Action required" content="Please set a new password" />
)

export default AlertExampleHeader
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleIcon = () => (
<Alert icon="exclamation-triangle" content="This is an alert with a warning icon" />
)

export default AlertExampleIcon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleIcon = () => (
<Alert icon="exclamation-triangle" content="This is an alert with a warning icon" />
)

export default AlertExampleIcon
10 changes: 10 additions & 0 deletions docs/src/examples/components/Alert/Slots/index.tsx
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ const Slots = () => (
description="An Alert can contain action buttons."
examplePath="components/Alert/Slots/AlertExampleActions"
/>
<ComponentExample
title="Icon"
description="An Alert can contain an icon."
examplePath="components/Alert/Slots/AlertExampleIcon"
/>
<ComponentExample
title="Header"
description="An Alert can contain a header."
examplePath="components/Alert/Slots/AlertExampleHeader"
/>
</ExampleSection>
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleImportantMessage = () => (
<Alert
warning
icon="exclamation-triangle"
header="Your password may have been compromised"
content="Please change your password"
dismissible
/>
)

export default AlertExampleImportantMessage
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react'
import { Alert } from '@stardust-ui/react'

const AlertExampleImportantMessage = () => (
<Alert
warning
icon="exclamation-triangle"
header="Your password may have been compromised"
content="Please change your password"
dismissible
/>
)

export default AlertExampleImportantMessage
5 changes: 5 additions & 0 deletions docs/src/examples/components/Alert/Usage/index.tsx
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ const Usage = () => (
description="You can also dismiss alerts on actions."
examplePath="components/Alert/Usage/AlertExampleDismissActions"
/>
<ComponentExample
title="Important message"
description="An Alert that displays an important information."
examplePath="components/Alert/Usage/AlertExampleImportantMessage"
/>
</ExampleSection>
)

Expand Down
59 changes: 57 additions & 2 deletions packages/react/src/components/Alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ import {
} from '../../types'
import Box, { BoxProps } from '../Box/Box'
import Button, { ButtonProps } from '../Button/Button'
import Icon, { IconProps } from '../Icon/Icon'
import Text, { TextProps } from '../Text/Text'

import ButtonGroup, { ButtonGroupProps } from '../Button/ButtonGroup'

export interface AlertSlotClassNames {
content: string
actions: string
dismissAction: string
icon: string
header: string
body: string
}

export interface AlertProps
Expand All @@ -44,6 +50,12 @@ export interface AlertProps
/** An Alert can contain action buttons. */
actions?: ShorthandValue<ButtonGroupProps> | ShorthandCollection<ButtonProps>

/** An alert may contain an icon. */
icon?: ShorthandValue<IconProps>

/** An alert may contain a header. */
header?: ShorthandValue<TextProps>

/** Controls Alert's relation to neighboring items. */
attached?: boolean | 'top' | 'bottom'

Expand Down Expand Up @@ -87,11 +99,15 @@ export interface AlertProps

/** An alert may be formatted to display a warning message. */
warning?: boolean

/** Body contains header and content elements. */
body?: ShorthandValue<BoxProps>
}

export interface AlertState {
isFromKeyboard: boolean
visible: boolean
bodyId: string
}

class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState> {
Expand All @@ -102,6 +118,9 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
content: `${Alert.className}__content`,
actions: `${Alert.className}__actions`,
dismissAction: `${Alert.className}__dismissAction`,
icon: `${Alert.className}__icon`,
header: `${Alert.className}__header`,
body: `${Alert.className}__body`,
}

static propTypes = {
Expand All @@ -110,6 +129,8 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
customPropTypes.itemShorthand,
customPropTypes.collectionShorthand,
]),
icon: customPropTypes.itemShorthandWithoutJSX,
header: customPropTypes.itemShorthand,
attached: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['top', 'bottom'])]),
danger: PropTypes.bool,
defaultVisible: PropTypes.bool,
Expand All @@ -121,11 +142,13 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
success: PropTypes.bool,
visible: PropTypes.bool,
warning: PropTypes.bool,
body: customPropTypes.itemShorthand,
}

static defaultProps = {
accessibility: alertBehavior,
dismissAction: { icon: 'close' },
body: {},
}

static autoControlledProps = ['visible']
Expand All @@ -134,6 +157,7 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
return {
isFromKeyboard: false,
visible: true,
bodyId: _.uniqueId('alert-body-'),
}
}

Expand All @@ -153,17 +177,47 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
}

renderContent = ({ styles, accessibility }: RenderResultConfig<AlertProps>) => {
const { actions, dismissible, dismissAction, content } = this.props
const { actions, dismissible, dismissAction, content, icon, header, body } = this.props

return (
const bodyContent = (
<>
{Text.create(header, {
defaultProps: {
className: Alert.slotClassNames.header,
styles: styles.header,
...accessibility.attributes.header,
},
})}
{Box.create(content, {
defaultProps: {
className: Alert.slotClassNames.content,
styles: styles.content,
...accessibility.attributes.content,
},
})}
</>
)

return (
<>
{Icon.create(icon, {
defaultProps: {
className: Alert.slotClassNames.icon,
styles: styles.icon,
},
})}
{Box.create(body, {
defaultProps: {
id: this.state.bodyId,
className: Alert.slotClassNames.body,
...accessibility.attributes.body,
styles: styles.body,
},
overrideProps: {
children: bodyContent,
},
})}

{ButtonGroup.create(actions, {
defaultProps: {
className: Alert.slotClassNames.actions,
Expand All @@ -177,6 +231,7 @@ class Alert extends AutoControlledComponent<WithAsProp<AlertProps>, AlertState>
text: true,
className: Alert.slotClassNames.dismissAction,
styles: styles.dismissAction,
...accessibility.attributes.dismissAction,
},
overrideProps: this.handleDismissOverrides,
})}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { Accessibility } from '../../types'
import alertWarningBehavior from './alertWarningBehavior'
import alertWarningBehavior, { AlertProps } from './alertWarningBehavior'

/**
* @description
* Uses `alertWarningBehavior` for 'danger' and 'warning' variants.
*/
const alertBehavior: Accessibility<AlertBehaviorProps> = props =>
const alertBehavior: Accessibility<AlertProps> = props =>
props.warning || props.danger ? alertWarningBehavior(props) : {}

export default alertBehavior

type AlertBehaviorProps = {
/** An alert may be formatted to display a danger message. */
danger?: boolean
/** An alert may be formatted to display a warning message. */
warning?: boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@ import { Accessibility } from '../../types'

/**
* @specification
* Adds role 'alert' to 'content' slot.
* Adds attribute 'aria-live=polite' to 'content' slot.
* Adds role 'alert' to 'body' slot.
* Adds attribute 'aria-live=polite' to 'body' slot.
*/

const alertWarningBehavior: Accessibility = () => ({
const alertWarningBehavior: Accessibility<AlertProps> = props => ({
attributes: {
content: {
body: {
role: 'alert',
'aria-live': 'polite',
},
dismissAction: {
'aria-describedby': props.bodyId,
},
},
})

export default alertWarningBehavior

export type AlertProps = {
/** An alert may be formatted to display a danger message. */
danger?: boolean
/** An alert may be formatted to display a warning message. */
warning?: boolean
/** Id of the alert body element. */
bodyId?: string
}
14 changes: 14 additions & 0 deletions packages/react/src/themes/teams/components/Alert/alertStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,24 @@ const alertStyles: ComponentSlotStylesInput<AlertProps, AlertVariables> = {
margin: v.actionsMargin,
}),

header: ({ variables: v }): ICSSInJSStyle => ({
fontWeight: v.headerFontWeight,
margin: v.headerMargin,
}),

body: (): ICSSInJSStyle => ({
display: 'flex',
flexGrow: 1,
}),

content: (): ICSSInJSStyle => ({
flexGrow: 1,
}),

icon: ({ variables: v }): ICSSInJSStyle => ({
margin: v.iconMargin,
}),

dismissAction: ({ variables: v, props: p, theme: { siteVariables } }): ICSSInJSStyle => {
const iconFilledStyles = getIconFillOrOutlineStyles({ outline: false })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export interface AlertVariables {
urgentColor: string
urgentBackgroundColor: string
urgentBorderColor: string

headerFontWeight: FontWeightProperty
headerMargin: string

iconMargin: string
}

export default (siteVars: SiteVariablesPrepared): AlertVariables => {
Expand Down Expand Up @@ -74,5 +79,10 @@ export default (siteVars: SiteVariablesPrepared): AlertVariables => {
urgentColor: siteVars.colors.white,
urgentBackgroundColor: siteVars.colors.red[400],
urgentBorderColor: siteVars.colors.red[400],

headerFontWeight: siteVars.fontWeightBold,
headerMargin: `0 ${pxToRem(10)} 0 0`,

iconMargin: `0 ${pxToRem(10)} 0 0`,
}
}
4 changes: 2 additions & 2 deletions packages/react/test/specs/behaviors/alertBehavior-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { alertBehavior } from 'src/lib/accessibility'
describe('AlertBehavior.ts', () => {
test('use alertWarningBehavior if warning prop is defined', () => {
const expectedResult = alertBehavior({ warning: true })
expect(expectedResult.attributes.content.role).toEqual('alert')
expect(expectedResult.attributes.body.role).toEqual('alert')
})

test('use alertWarningBehavior if danger prop is defined', () => {
const expectedResult = alertBehavior({ danger: true })
expect(expectedResult.attributes.content.role).toEqual('alert')
expect(expectedResult.attributes.body.role).toEqual('alert')
})
})
4 changes: 2 additions & 2 deletions packages/react/test/specs/components/Alert/Alert-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ describe('Alert', () => {
handlesAccessibility(Alert, { defaultRootRole: undefined, requiredProps: { content: 'test' } })
handlesAccessibility(Alert, {
defaultRootRole: undefined,
partSelector: `.${Alert.slotClassNames.content}`,
partSelector: `.${Alert.slotClassNames.body}`,
requiredProps: { content: 'test' },
})
handlesAccessibility(Alert, {
defaultRootRole: 'alert',
partSelector: `.${Alert.slotClassNames.content}`,
partSelector: `.${Alert.slotClassNames.body}`,
requiredProps: { content: 'test', warning: true },
})

Expand Down