-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: messagebar: add message bar component (#622)
* feat: messagebar: add message bar component * chore: messagebar: update icons per spec * chore: messagebar: export component * chore: messagebar: address pr feedback by adding a mapping
- Loading branch information
1 parent
9a8d34a
commit 421d785
Showing
9 changed files
with
679 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import React from 'react'; | ||
import { Stories } from '@storybook/addon-docs'; | ||
import { ComponentStory, ComponentMeta } from '@storybook/react'; | ||
import { MessageBar, MessageBarType } from '.'; | ||
import { IconName } from '../Icon'; | ||
|
||
export default { | ||
title: 'Message Bar', | ||
parameters: { | ||
docs: { | ||
page: (): JSX.Element => ( | ||
<main> | ||
<article> | ||
<section> | ||
<h1>Message Bar</h1> | ||
<p> | ||
These alret banners run across the whole viewport of the | ||
interface. They are to be put at the top of the page to alert | ||
the important message to the user. Depending on the severeity | ||
and context of the alert, these banners can have close button on | ||
the right and another CTA for the users to take action. | ||
</p> | ||
</section> | ||
<section> | ||
<Stories includePrimary title="" /> | ||
</section> | ||
</article> | ||
</main> | ||
), | ||
}, | ||
}, | ||
} as ComponentMeta<typeof MessageBar>; | ||
|
||
const Neutral_Story: ComponentStory<typeof MessageBar> = (args) => ( | ||
<MessageBar {...args} /> | ||
); | ||
|
||
export const Neutral = Neutral_Story.bind({}); | ||
|
||
const Positive_Story: ComponentStory<typeof MessageBar> = (args) => ( | ||
<MessageBar {...args} /> | ||
); | ||
|
||
export const Positive = Positive_Story.bind({}); | ||
|
||
const Warning_Story: ComponentStory<typeof MessageBar> = (args) => ( | ||
<MessageBar {...args} /> | ||
); | ||
|
||
export const Warning = Warning_Story.bind({}); | ||
|
||
const Disruptive_Story: ComponentStory<typeof MessageBar> = (args) => ( | ||
<MessageBar {...args} /> | ||
); | ||
|
||
export const Disruptive = Disruptive_Story.bind({}); | ||
|
||
const messageBarArgs: Object = { | ||
actionButtonProps: { | ||
ariaLabel: 'Action', | ||
classNames: 'my-action-btn-class', | ||
'data-test-id': 'my-action-btn-test-id', | ||
iconProps: null, | ||
id: 'myActionButton', | ||
text: 'Action', | ||
}, | ||
closable: true, | ||
header: 'Header 4 used in this MessageBar', | ||
content: | ||
'Body 2 which is at 16px font size is used here in the body section of the MessageBar. The body text can wrap to multiple lines and the buttons will be vertically centered.', | ||
style: {}, | ||
classNames: 'my-message-bar-class', | ||
closeButtonProps: { | ||
classNames: 'my-close-btn-class', | ||
'data-test-id': 'my-close-btn-test-id', | ||
id: 'myCloseButton', | ||
}, | ||
closeIcon: IconName.mdiClose, | ||
icon: IconName.mdiCheckCircle, | ||
role: 'alert', | ||
type: MessageBarType.positive, | ||
}; | ||
|
||
Neutral.args = { | ||
...messageBarArgs, | ||
icon: IconName.mdiInformation, | ||
type: MessageBarType.neutral, | ||
}; | ||
|
||
Positive.args = { | ||
...messageBarArgs, | ||
}; | ||
|
||
Warning.args = { | ||
...messageBarArgs, | ||
icon: IconName.mdiAlert, | ||
type: MessageBarType.warning, | ||
}; | ||
|
||
Disruptive.args = { | ||
...messageBarArgs, | ||
icon: IconName.mdiAlertCircle, | ||
type: MessageBarType.disruptive, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import React, { FC, Ref, useEffect, useState } from 'react'; | ||
import { MessageBarsProps, MessageBarType } from './MessageBar.types'; | ||
import { InfoBarLocale } from '../InfoBar/InfoBar.types'; | ||
import { Icon, IconName } from '../Icon'; | ||
import { mergeClasses } from '../../shared/utilities'; | ||
import { ButtonShape, NeutralButton } from '../Button'; | ||
import LocaleReceiver, { | ||
useLocaleReceiver, | ||
} from '../LocaleProvider/LocaleReceiver'; | ||
import enUS from '../InfoBar/Locale/en_US'; | ||
|
||
import styles from './messageBar.module.scss'; | ||
|
||
export const MessageBar: FC<MessageBarsProps> = React.forwardRef( | ||
(props: MessageBarsProps, ref: Ref<HTMLDivElement>) => { | ||
const { | ||
actionButtonProps, | ||
classNames, | ||
closable, | ||
closeButtonAriaLabelText: defaultCloseButtonAriaLabelText, | ||
closeButtonProps, | ||
closeIcon = IconName.mdiClose, | ||
content, | ||
header, | ||
icon, | ||
locale = enUS, | ||
onClose, | ||
role = 'alert', | ||
style, | ||
type = MessageBarType.neutral, | ||
...rest | ||
} = props; | ||
|
||
// ============================ Strings =========================== | ||
const [infoBarLocale] = useLocaleReceiver('InfoBar'); | ||
let mergedLocale: InfoBarLocale; | ||
|
||
if (props.locale) { | ||
mergedLocale = props.locale; | ||
} else { | ||
mergedLocale = infoBarLocale || props.locale; | ||
} | ||
|
||
const [closeButtonAriaLabelText, setCloseButtonAriaLabelText] = | ||
useState<string>(defaultCloseButtonAriaLabelText); | ||
|
||
// Locs: if the prop isn't provided use the loc defaults. | ||
// If the mergedLocale is changed, update. | ||
useEffect(() => { | ||
setCloseButtonAriaLabelText( | ||
props.closeButtonAriaLabelText | ||
? props.closeButtonAriaLabelText | ||
: mergedLocale.lang!.closeButtonAriaLabelText | ||
); | ||
}, [mergedLocale]); | ||
|
||
const messageBarClassNames: string = mergeClasses([ | ||
styles.messageBar, | ||
classNames, | ||
{ [styles.neutral]: type === MessageBarType.neutral }, | ||
{ [styles.positive]: type === MessageBarType.positive }, | ||
{ [styles.warning]: type === MessageBarType.warning }, | ||
{ [styles.disruptive]: type === MessageBarType.disruptive }, | ||
]); | ||
|
||
const messageBarTypeToIconNameMap = new Map<MessageBarType, IconName>([ | ||
[MessageBarType.disruptive, IconName.mdiAlertCircle], | ||
[MessageBarType.neutral, IconName.mdiInformation], | ||
[MessageBarType.positive, IconName.mdiCheckCircle], | ||
[MessageBarType.warning, IconName.mdiAlert], | ||
]); | ||
|
||
const getIconName = (): IconName => { | ||
if (icon) { | ||
return icon; | ||
} | ||
return messageBarTypeToIconNameMap.get(type); | ||
}; | ||
|
||
return ( | ||
<LocaleReceiver componentName={'InfoBar'} defaultLocale={enUS}> | ||
{(_contextLocale: InfoBarLocale) => { | ||
return ( | ||
<div | ||
{...rest} | ||
className={messageBarClassNames} | ||
ref={ref} | ||
style={style} | ||
role={role} | ||
> | ||
<Icon path={getIconName()} classNames={styles.icon} /> | ||
<div className={styles.message}> | ||
{header && <h4 className={styles.header}>{header}</h4>} | ||
<div className={styles.innerMessage}>{content}</div> | ||
</div> | ||
{(actionButtonProps || closable) && ( | ||
<div className={styles.actions}> | ||
{actionButtonProps && ( | ||
<NeutralButton {...actionButtonProps} /> | ||
)} | ||
{closable && ( | ||
<NeutralButton | ||
ariaLabel={closeButtonAriaLabelText} | ||
iconProps={{ path: closeIcon }} | ||
onClick={onClose} | ||
shape={ButtonShape.Round} | ||
{...closeButtonProps} | ||
/> | ||
)} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}} | ||
</LocaleReceiver> | ||
); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from 'react'; | ||
import { InfoBarsProps } from '../InfoBar'; | ||
|
||
export enum MessageBarType { | ||
neutral = 'neutral', | ||
positive = 'positive', | ||
warning = 'warning', | ||
disruptive = 'disruptive', | ||
} | ||
|
||
export interface MessageBarsProps extends Omit<InfoBarsProps, 'type'> { | ||
/** | ||
* Header of the MessageBar | ||
*/ | ||
header?: React.ReactNode; | ||
/** | ||
* Type of the MessageBar | ||
* @default MessageBarType.neutral | ||
*/ | ||
type?: MessageBarType; | ||
} |
Oops, something went wrong.