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

feat(GlobalStatus): Add warning and success states and Sbanken style #2584

Merged
merged 11 commits into from
Aug 25, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: 'GlobalStatus'
description: 'The GlobalStatus is a complex component meant for displaying global Application notifications or a summary of a form.'
showTabs: true
theme: 'sbanken'
---

import GlobalStatusComponentInfo from 'Docs/uilib/components/global-status/info'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,36 @@ export const GlobalStatusInfo = () => (
</ComponentBox>
)

export const GlobalStatusWarning = () => (
<ComponentBox>
<GlobalStatus
state="warning"
title="Custom warning title ..."
text="A string of text providing a warning or semi-urgent message of some kind to the user"
show={true}
autoscroll={false}
no_animation={true}
omit_set_focus={true}
id="demo-5"
/>
</ComponentBox>
)

export const GlobalStatusSuccess = () => (
<ComponentBox>
<GlobalStatus
state="success"
title="Custom success title ..."
text="A string of text providing a success message of some kind to the user"
show={true}
autoscroll={false}
no_animation={true}
omit_set_focus={true}
id="demo-6"
/>
</ComponentBox>
)

export const GlobalStatusCoupling = () => (
<ComponentBox>
{() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ showTabs: true
import {
GlobalStatusError,
GlobalStatusInfo,
GlobalStatusWarning,
GlobalStatusSuccess,
GlobalStatusUpdate,
GlobalStatusCoupling,
GlobalStatusAddRemoveItems,
Expand All @@ -23,6 +25,14 @@ import {

<GlobalStatusInfo />

### GlobalStatus displaying warning status

<GlobalStatusWarning />

### GlobalStatus displaying success status

<GlobalStatusSuccess />

### To showcase the automated coupling between **FormStatus** and **GlobalStatus**

<GlobalStatusCoupling />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@
.dnb-sidebar-menu__theme-badge__title {
width: 0.7em;
overflow: hidden;
padding: 0.0625rem;
height: 1.5rem;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love if we could move height to be together with "width".

ref. rational css properties order 👍

}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type FormStatusState =
| 'error'
| 'warn'
| 'info'
| 'success'
| 'marketing';
export type FormStatusVariant = 'flat' | 'outlined';
export type FormStatusSize = 'default' | 'large';
Expand Down
102 changes: 58 additions & 44 deletions packages/dnb-eufemia/src/components/form-status/FormStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,35 +125,36 @@ export default class FormStatus extends React.PureComponent {
return state
}

static getIcon({ state, icon, icon_size }) {
if (typeof icon === 'string') {
let IconToLoad = icon
static getIcon({ state, icon, icon_size, theme }) {
if (typeof icon !== 'string') {
return icon
}

switch (FormStatus.correctStatus(state)) {
case 'info':
IconToLoad = InfoIcon
break
case 'warn':
IconToLoad = WarnIcon
break
case 'marketing':
IconToLoad = MarketingIcon
break
case 'error':
default:
IconToLoad = ErrorIcon
}
let IconToLoad = icon

icon = (
<Icon
icon={<IconToLoad title={null} />}
size={icon_size}
inherit_color={false}
/>
)
switch (FormStatus.correctStatus(state)) {
case 'info':
case 'success':
IconToLoad = InfoIcon
break
case 'warn':
IconToLoad = WarnIcon
break
case 'marketing':
IconToLoad = MarketingIcon
break
case 'error':
default:
IconToLoad = ErrorIcon
}

return icon
return (
<Icon
icon={<IconToLoad title={null} state={state} theme={theme} />}
size={icon_size}
inherit_color={false}
/>
)
}

static getDerivedStateFromProps(props, state) {
Expand Down Expand Up @@ -369,6 +370,7 @@ export default class FormStatus extends React.PureComponent {
state,
icon,
icon_size,
theme: this.context?.theme?.name
})

const contentToRender =
Expand Down Expand Up @@ -499,30 +501,42 @@ WarnIcon.defaultProps = {
title: 'error',
}

export const InfoIcon = (props) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
{props && props.title && <title>{props.title}</title>}
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.268 0a11.25 11.25 0 105.566 21.017l6.112 2.91a.75.75 0 001-1l-2.911-6.112A11.234 11.234 0 0011.268 0z"
fill="#007272"
/>
<circle cx="11" cy="6.5" r=".5" fill="#fff" stroke="#fff" />
<path
d="M13.75 16H13a1.5 1.5 0 01-1.5-1.5v-3.75a.75.75 0 00-.75-.75H10"
stroke="#fff"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
export const InfoIcon = props => {
const isSbankenTheme = props && props?.theme === 'sbanken';
let fill = isSbankenTheme ? '#000' : '#007272'
if (props && props?.state === 'success') {
fill = isSbankenTheme ? '#02A56A' : '#28B482'
}

return (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
{props && props.title && <title>{props.title}</title>}
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.268 0a11.25 11.25 0 105.566 21.017l6.112 2.91a.75.75 0 001-1l-2.911-6.112A11.234 11.234 0 0011.268 0z"
fill={fill}
/>
<circle cx="11" cy="6.5" r=".5" fill="#fff" stroke="#fff" />
<path
d="M13.75 16H13a1.5 1.5 0 01-1.5-1.5v-3.75a.75.75 0 00-.75-.75H10"
stroke="#fff"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
InfoIcon.propTypes = {
title: PropTypes.string,
state: PropTypes.string,
theme: PropTypes.string,
}
InfoIcon.defaultProps = {
title: 'info',
state: 'info',
theme: 'ui'
}

export const MarketingIcon = (props) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type GlobalStatusText =
| ((...args: any[]) => any)
| React.ReactNode;
export type GlobalStatusItem = string | ((...args: any[]) => any) | any;
export type GlobalStatusState = 'error' | 'info';
export type GlobalStatusState = 'error' | 'info' | 'warning' | 'success';
export type GlobalStatusShow = 'auto' | any | any | 'true' | 'false';
export type GlobalStatusDelay = string | number;
export type GlobalStatusConfigObject = {
Expand Down
19 changes: 12 additions & 7 deletions packages/dnb-eufemia/src/components/global-status/GlobalStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import GlobalStatusController, {
} from './GlobalStatusController'
import GlobalStatusProvider from './GlobalStatusProvider'
import Icon from '../icon/Icon'
import { InfoIcon, ErrorIcon } from '../form-status/FormStatus'
import { InfoIcon, ErrorIcon, WarnIcon } from '../form-status/FormStatus'
import Section from '../section/Section'
import Button from '../button/Button'

Expand Down Expand Up @@ -60,7 +60,7 @@ export default class GlobalStatus extends React.PureComponent {
PropTypes.node,
]),
icon_size: PropTypes.string,
state: PropTypes.oneOf(['error', 'info']),
state: PropTypes.oneOf(['error', 'info', 'warning', 'success']),
show: PropTypes.oneOf(['auto', true, false, 'true', 'false']),
autoscroll: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
autoclose: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
Expand Down Expand Up @@ -137,23 +137,28 @@ export default class GlobalStatus extends React.PureComponent {
return processChildren(props)
}

static getIcon({ state, icon, icon_size }) {
static getIcon({ state, icon, icon_size, theme }) {
if (typeof icon === 'string') {
let IconToLoad = icon

switch (state) {
case 'info':
case 'information':
case 'success':
IconToLoad = InfoIcon
break
case 'warning':
case 'warn':
IconToLoad = WarnIcon
break
case 'error':
default:
IconToLoad = ErrorIcon
}

icon = (
<Icon
icon={<IconToLoad />}
icon={<IconToLoad state={state} theme={theme} />}
size={icon_size}
inherit_color={false}
/>
Expand Down Expand Up @@ -694,13 +699,13 @@ export default class GlobalStatus extends React.PureComponent {
state,
icon: icon || fallbackProps.icon,
icon_size: icon_size || fallbackProps.icon_size,
theme: this.context?.theme?.name || 'ui'
})
const titleToRender =
title || fallbackProps.title || fallbackProps.default_title
const noAnimation = isTrue(no_animation)
const itemsToRender = props.items || []
const contentToRender = GlobalStatus.getContent(props)
const style = state === 'info' ? 'pistachio' : 'fire-red-8'

/**
* Show aria-live="assertive" when:
Expand Down Expand Up @@ -746,7 +751,7 @@ export default class GlobalStatus extends React.PureComponent {
const renderedContent = (
<div className="dnb-global-status__content">
{title !== false && (
<Section element="div" style_type={style}>
<Section element="div" variant={state}>
<p className="dnb-p dnb-global-status__title" lang={lang}>
<span className="dnb-global-status__icon">
{iconToRender}
Expand All @@ -768,7 +773,7 @@ export default class GlobalStatus extends React.PureComponent {
{hasContent && (
<Section
element="div"
style_type={style}
variant={state}
className="dnb-global-status__message"
>
<div className="dnb-global-status__message__content">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import {

const style = { width: '25rem' }

describe('GlobalStatus', () => {
setupPageScreenshot({ url: '/uilib/components/global-status/demos' })
describe.each(['ui', 'sbanken'])('GlobalStatus for %s', themeName => {
setupPageScreenshot({
themeName,
url: '/uilib/components/global-status/demos'
})

it('have to match the default state with custom content', async () => {
const screenshot = await makeScreenshot({
Expand All @@ -30,25 +33,27 @@ describe('GlobalStatus', () => {
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the close button in focus state', async () => {
const screenshot = await makeScreenshot({
style,
selector: '[data-visual-test="global-status"] .dnb-global-status',
simulateSelector:
'[data-visual-test="global-status"] .dnb-global-status__close-button',
simulate: 'focus',
if (themeName !== 'sbanken') {
it('have to match the close button in focus state', async () => {
const screenshot = await makeScreenshot({
style,
selector: '[data-visual-test="global-status"] .dnb-global-status',
simulateSelector:
'[data-visual-test="global-status"] .dnb-global-status__close-button',
simulate: 'focus',
})
expect(screenshot).toMatchImageSnapshot()
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match the close button in hover state', async () => {
const screenshot = await makeScreenshot({
style,
selector: '[data-visual-test="global-status"] .dnb-global-status',
simulateSelector:
'[data-visual-test="global-status"] .dnb-global-status__close-button',
simulate: 'hover',
it('have to match the close button in hover state', async () => {
const screenshot = await makeScreenshot({
style,
selector: '[data-visual-test="global-status"] .dnb-global-status',
simulateSelector:
'[data-visual-test="global-status"] .dnb-global-status__close-button',
simulate: 'hover',
})
expect(screenshot).toMatchImageSnapshot()
})
expect(screenshot).toMatchImageSnapshot()
})
}
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -734,9 +734,6 @@ exports[`GlobalStatus scss have to match default theme snapshot 1`] = `
.dnb-global-status__icon {
font-size: 1rem;
}
.dnb-global-status__message__content {
color: var(--color-black-80);
}
.dnb-global-status__message.dnb-section--white ::selection {
background-color: var(--color-mint-green);
}
Expand All @@ -745,5 +742,11 @@ exports[`GlobalStatus scss have to match default theme snapshot 1`] = `
}
.dnb-global-status--info .dnb-global-status__content .dnb-hr {
color: var(--color-sea-green);
}
.dnb-global-status--warning .dnb-global-status__content .dnb-hr {
color: var(--color-accent-yellow);
}
.dnb-global-status--success .dnb-global-status__content .dnb-hr {
color: var(--color-ocean-green);
}"
`;
Loading