Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Banner component #1036

Merged
merged 37 commits into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
141cea5
Initial commit
m-akinc Jan 23, 2023
ccc939e
Fix styling issues and add action link/button
m-akinc Jan 25, 2023
8466034
First round of feedback - significant revisions
m-akinc Jan 30, 2023
a00e17a
Create matrix stories
m-akinc Jan 30, 2023
879d9fc
Prettier fixes
m-akinc Jan 30, 2023
7301617
Use tokens for banner styles
m-akinc Jan 30, 2023
32cda92
Add wrapping story
m-akinc Jan 30, 2023
ca18bec
Change files
m-akinc Jan 30, 2023
19469ec
Update README
m-akinc Jan 30, 2023
3841135
Polish
m-akinc Feb 7, 2023
7c633db
Set aria-label from title
m-akinc Feb 7, 2023
5043e5a
Prettier fixes
m-akinc Feb 7, 2023
23a1a93
Add tests
m-akinc Feb 7, 2023
9fe05c9
More documentation
m-akinc Feb 7, 2023
291386e
Fix token naming violations
m-akinc Feb 8, 2023
8a265f6
Fix another token naming violation
m-akinc Feb 8, 2023
351e6df
Change "close" to "dismiss"
m-akinc Feb 8, 2023
3c32d5d
Remove most banner tokens
m-akinc Feb 8, 2023
33382c6
Dismiss button focus styling
m-akinc Feb 8, 2023
ef4b98a
Add test for BannerSeverity
m-akinc Feb 8, 2023
a377126
Fix build error
m-akinc Feb 9, 2023
61052ca
Add padding and fix color theme transparency issue
m-akinc Feb 9, 2023
ed3b034
Address some feedback
m-akinc Feb 9, 2023
9244d0e
Change token name and reorg theme/severity styles
m-akinc Feb 10, 2023
e6d5686
Fix build
m-akinc Feb 10, 2023
53d58df
Fix typo
m-akinc Feb 10, 2023
6aad68d
Fix other typo
m-akinc Feb 10, 2023
d91555d
Fix styles
m-akinc Feb 10, 2023
b1d6117
Update packages/nimble-components/src/banner/tests/banner.stories.ts
m-akinc Feb 13, 2023
d4067d7
Molly's feedback
m-akinc Feb 13, 2023
8359ced
Lint fix
m-akinc Feb 13, 2023
6e0c924
More feedback
m-akinc Feb 13, 2023
6bd7836
Bunch of feedback
m-akinc Feb 15, 2023
91054de
Minor css change
m-akinc Feb 15, 2023
cb6da7a
Merge branch 'main' into users/makinc/banner
m-akinc Feb 15, 2023
e104e8c
Trying to fix prettier issues
m-akinc Feb 15, 2023
c49f6b9
Again trying to fix prettier issue
m-akinc Feb 15, 2023
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ NOTE: To update the component status:
| Accordion | | [Issue](https://github.com/ni/nimble/issues/533) | :o: | :o: | :o: |
| Anchor | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/bfadf499-caf5-4ca0-9814-e777fbae0d46/) | [Issue](https://github.com/ni/nimble/issues/324) | [:white_check_mark: - SB](https://ni.github.io/nimble/storybook/?path=/docs/anchor--text-anchor) | :white_check_mark: | :white_check_mark: |
| Anchor Button | | [Issue](https://github.com/ni/nimble/issues/324) | [:white_check_mark: - SB](https://ni.github.io/nimble/storybook/?path=/docs/anchor-button--outline-anchor-button) | :white_check_mark: | :white_check_mark: |
| Anchor Tabs | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/b2aa2c0c-03b7-4571-8e0d-de88baf0814b) | [Issue](https://github.com/ni/nimble/issues/479) | [:white_check_mark: - SB](https://nimble.ni.dev/storybook/?path=/docs/anchor-tabs--tabs) | :o: | :o: |
| Banners | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/29c405f7-08ea-48b6-973f-546970b9dbab) | [Issue](https://github.com/ni/nimble/issues/305) | :o: | :o: | :o: |
| Anchor Tabs | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/b2aa2c0c-03b7-4571-8e0d-de88baf0814b) | [Issue](https://github.com/ni/nimble/issues/479) | [:white_check_mark: - SB](https://nimble.ni.dev/storybook/?path=/docs/anchor-tabs--anchor-tabs) | :white_check_mark: | :white_check_mark: |
| Banner | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/29c405f7-08ea-48b6-973f-546970b9dbab) | [Issue](https://github.com/ni/nimble/issues/305) | [:white_check_mark: - SB](https://nimble.ni.dev/storybook/?path=/docs/banner--banner) | :o: | :o: |
| Breadcrumb | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/7b53bb3e-439b-4f13-9d5f-55adc7da8a2e) | | [:white_check_mark: - SB](https://ni.github.io/nimble/storybook/?path=/docs/breadcrumb--standard-breadcrumb) | :white_check_mark: | :white_check_mark: |
| Card | | [Issue](https://github.com/ni/nimble/issues/296) | :o: | :o: | :o: |
| Card button | [XD](https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/d4ebeb5d-023c-4ff2-a71c-f6385fffca20) | [Issue](https://github.com/ni/nimble/issues/643) | [:white_check_mark: - SB](https://ni.github.io/nimble/storybook/?path=/docs/card-button--card-button) | :white_check_mark: | :white_check_mark: |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Banner component",
"packageName": "@ni/nimble-components",
"email": "7282195+m-akinc@users.noreply.github.com",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions packages/nimble-components/src/all-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import './anchor-button';
import './anchor-tab';
import './anchor-tabs';
import './anchored-region';
import './banner';
import './breadcrumb';
import './breadcrumb-item';
import './button';
Expand Down
89 changes: 89 additions & 0 deletions packages/nimble-components/src/banner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { attr, observable } from '@microsoft/fast-element';
import { DesignSystem, FoundationElement } from '@microsoft/fast-foundation';
import { styles } from './styles';
import { template } from './template';
import { BannerSeverity } from './types';

declare global {
interface HTMLElementTagNameMap {
'nimble-banner': Banner;
}
}

/**
* A nimble-styled notification banner for persistent messages.
*/
export class Banner extends FoundationElement {
/**
* @public
* @description
* Whether the banner is visible or not
*/
@attr({ mode: 'boolean' })
public open = false;

/**
* @public
* @description
* Severity of the banner's message
*/
@attr()
public severity: BannerSeverity = BannerSeverity.default;

/**
* @public
* @description
* Whether the banner title is hidden
*/
@attr({ attribute: 'title-hidden', mode: 'boolean' })
public titleHidden = false;

/**
* @public
* @description
* Hides the dismiss button
*/
@attr({ attribute: 'prevent-dismiss', mode: 'boolean' })
public preventDismiss = false;

/**
* @public
* @description
* Label (not visible) for the dismiss button
*/
@attr({ attribute: 'dismiss-button-label' })
public dismissButtonLabel?: string;

/** @internal */
@observable
public readonly slottedTitle?: HTMLElement[];

/**
* @internal
*/
public openChanged(): void {
this.$emit('toggle', { oldState: !this.open, newState: this.open });
}

/**
* @internal
*/
public closeBanner(): void {
this.open = false;
}

/**
* @internal
*/
public getAriaLabel(): string {
return this.slottedTitle ? this.slottedTitle[0]?.innerText ?? '' : '';
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
}
}

const nimbleBanner = Banner.compose({
baseName: 'banner',
template,
styles
});

DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleBanner());
157 changes: 157 additions & 0 deletions packages/nimble-components/src/banner/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { css } from '@microsoft/fast-element';
import { display } from '@microsoft/fast-foundation';

import {
actionRgbPartialColor,
bannerButtonFillSelectedColor,
bannerButtonHeight,
bannerCloseButtonIconSize,
bannerCloseButtonSize,
bannerColor,
bannerErrorBackgroundColor,
bannerFontSize,
bannerIconColor,
bannerIconMarginTop,
bannerInfoBackgroundColor,
bannerLinkActiveFontColor,
bannerNeutralBackgroundColor,
bannerStartEndWidth,
bannerTextGap,
bannerTextMarginVertical,
bannerWarningBackgroundColor,
bodyFont,
borderHoverColor,
buttonLabelFontColor,
controlHeight,
fillSelectedColor,
iconColor,
iconSize,
linkActiveFontColor,
linkDisabledFontColor,
linkFontColor
} from '../theme-provider/design-tokens';
import { MultivaluePropertyStyleSheetBehavior } from '../utilities/style/multivalue-property-stylesheet-behavior';
import { BannerSeverity } from './types';

export const styles = css`
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
${display('flex')}

:host {
width: 100%;
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
font: ${bodyFont};
font-size: ${bannerFontSize};
align-items: top;
overflow: hidden;
background: ${bannerNeutralBackgroundColor};
color: ${bannerColor};
${iconColor.cssCustomProperty}: ${bannerIconColor};
}

:host(:not([open])) {
display: none;
}

.icon {
width: ${bannerStartEndWidth};
display: flex;
justify-content: center;
margin-top: ${bannerIconMarginTop};
flex: 0 0 auto;
}

.text {
display: inline;
margin-top: ${bannerTextMarginVertical};
margin-bottom: ${bannerTextMarginVertical};
}

::slotted([slot='title']) {
font-weight: bold;
padding-right: ${bannerTextGap};
white-space: nowrap;
}

.controls {
margin-left: auto;
display: flex;
justify-content: center;
}

slot[name='action'] {
display: flex;
align-content: center;
}

::slotted(nimble-anchor[slot='action']) {
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
${linkFontColor.cssCustomProperty}: ${bannerColor};
${linkDisabledFontColor.cssCustomProperty}: ${bannerColor};
${linkActiveFontColor.cssCustomProperty}: ${bannerLinkActiveFontColor};
white-space: nowrap;
margin-top: ${bannerTextMarginVertical};
}

::slotted(nimble-button[slot='action']) {
height: 24px;
${buttonLabelFontColor.cssCustomProperty}: ${bannerColor};
${fillSelectedColor.cssCustomProperty}: ${bannerButtonFillSelectedColor};
${borderHoverColor.cssCustomProperty}: ${bannerColor};
white-space: nowrap;
margin-top: calc((${controlHeight} - ${bannerButtonHeight}) / 2);
}

::slotted(nimble-button[slot='action'][appearance='outline']) {
${actionRgbPartialColor.cssCustomProperty}: ${bannerColor}
}

.close {
width: ${bannerStartEndWidth};
display: flex;
justify-content: center;
margin-top: ${bannerIconMarginTop};
}

.close nimble-button {
height: ${bannerCloseButtonSize};
width: ${bannerCloseButtonSize};
${iconSize.cssCustomProperty}: ${bannerCloseButtonIconSize};
${buttonLabelFontColor.cssCustomProperty}: ${bannerColor};
${borderHoverColor.cssCustomProperty}: transparent;
${fillSelectedColor.cssCustomProperty}: ${bannerButtonFillSelectedColor};
}

.close nimble-button:hover {
background: ${bannerButtonFillSelectedColor};
}
`.withBehaviors(
new MultivaluePropertyStyleSheetBehavior(
'severity',
BannerSeverity.error,
css`
:host {
background: ${bannerErrorBackgroundColor};
}
`
),
new MultivaluePropertyStyleSheetBehavior(
'severity',
BannerSeverity.warning,
css`
:host {
background: ${bannerWarningBackgroundColor};
}
`
),
new MultivaluePropertyStyleSheetBehavior(
'severity',
BannerSeverity.info,
css`
:host {
background: ${bannerInfoBackgroundColor};
}

.icon {
${iconSize.cssCustomProperty}: 18px;
}
`
)
);
42 changes: 42 additions & 0 deletions packages/nimble-components/src/banner/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { html, slotted, when } from '@microsoft/fast-element';
import { DesignSystem } from '@microsoft/fast-foundation';
import type { Banner } from '.';
import { Button } from '../button';
import { IconExclamationMark } from '../icons/exclamation-mark';
import { IconInfo } from '../icons/info';
import { IconTriangleFilled } from '../icons/triangle-filled';
import { IconXmark } from '../icons/xmark';

// prettier-ignore
export const template = html<Banner>`
<template role="status" aria-label=${x => x.getAriaLabel()}>
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
<div class="icon">
${when(x => x.severity === 'error', html`
<${DesignSystem.tagFor(IconExclamationMark)}></${DesignSystem.tagFor(IconExclamationMark)}>
`)}
${when(x => x.severity === 'warning', html`
<${DesignSystem.tagFor(IconTriangleFilled)}></${DesignSystem.tagFor(IconTriangleFilled)}>
`)}
${when(x => x.severity === 'info', html`
<${DesignSystem.tagFor(IconInfo)}></${DesignSystem.tagFor(IconInfo)}>
`)}
</div>
<div class="text">
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
${when(x => !x.titleHidden, html`
<slot name="title" ${slotted('slottedTitle')}></slot>
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
`)}
<slot></slot>
</div>
<div class="controls">
<slot name="action"></slot>
<div class="close">
${when(x => !x.preventDismiss, html<Banner>`
m-akinc marked this conversation as resolved.
Show resolved Hide resolved
<${DesignSystem.tagFor(Button)} appearance="ghost" content-hidden @click="${x => x.closeBanner()}">
<${DesignSystem.tagFor(IconXmark)} slot="start"></${DesignSystem.tagFor(IconXmark)}>
${x => x.dismissButtonLabel}
</${DesignSystem.tagFor(Button)}>
`)}
</div>
</div>
</template>
`;
Loading