-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): add alert component (#1085)
Co-authored-by: Philipp Gfeller <[email protected]> Co-authored-by: Loïc Fürhoff <[email protected]>
- Loading branch information
1 parent
43b6ac2
commit d487840
Showing
32 changed files
with
1,044 additions
and
383 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,5 @@ | ||
--- | ||
'@swisspost/design-system-styles': patch | ||
--- | ||
|
||
Reduced the gap between the alert body and action buttons. |
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,6 @@ | ||
--- | ||
'@swisspost/design-system-documentation': minor | ||
'@swisspost/design-system-components': minor | ||
--- | ||
|
||
Created the web component variant for the alert component. |
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
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,30 @@ | ||
describe('alert', () => { | ||
describe('default', () => { | ||
beforeEach(() => { | ||
cy.getComponent('post-alert'); | ||
}); | ||
|
||
it('should render', () => { | ||
cy.get('@alert').should('exist'); | ||
}); | ||
|
||
it('should not have a close button', () => { | ||
cy.get('@alert').find('.btn-close').should('not.exist'); | ||
}); | ||
}); | ||
|
||
describe('dismissible', () => { | ||
beforeEach(() => { | ||
cy.getComponent('post-alert', 'dismissible'); | ||
}); | ||
|
||
it('should have a close button', () => { | ||
cy.get('@alert').find('.btn-close').should('be.visible'); | ||
}); | ||
|
||
it('should be removed after the dismiss button is clicked', () => { | ||
cy.get('@alert').find('.btn-close').click(); | ||
cy.get('@alert').should('not.exist'); | ||
}); | ||
}); | ||
}); |
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
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
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,3 @@ | ||
export const ALERT_TYPES = ['primary', 'success', 'danger', 'warning', 'info', 'gray'] as const; | ||
|
||
export type AlertType = typeof ALERT_TYPES[number]; |
22 changes: 22 additions & 0 deletions
22
packages/components/src/components/post-alert/post-alert.scss
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,22 @@ | ||
@use '@swisspost/design-system-styles/components/alert'; | ||
@use '@swisspost/design-system-styles/components/close'; | ||
@use '@swisspost/design-system-styles/core' as post; | ||
|
||
:host { | ||
display: block; | ||
|
||
::slotted(*) { | ||
margin: 0 !important; | ||
} | ||
} | ||
|
||
.visually-hidden { | ||
@include post.visually-hidden(); | ||
} | ||
|
||
@for $i from 1 through 6 { | ||
.alert-heading > ::slotted(h#{$i}) { | ||
font-size: inherit !important; | ||
font-weight: inherit !important; | ||
} | ||
} |
153 changes: 153 additions & 0 deletions
153
packages/components/src/components/post-alert/post-alert.tsx
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,153 @@ | ||
import { Component, Element, Event, EventEmitter, h, Host, Method, Prop, State, Watch } from '@stencil/core'; | ||
import { version } from '../../../package.json'; | ||
import { fadeOut } from '../../animations'; | ||
import { checkEmptyOrOneOf, checkEmptyOrPattern, checkNonEmpty, checkType } from '../../utils'; | ||
import { ALERT_TYPES, AlertType } from './alert-types'; | ||
|
||
@Component({ | ||
tag: 'post-alert', | ||
styleUrl: 'post-alert.scss', | ||
shadow: true, | ||
}) | ||
export class PostAlert { | ||
@Element() host: HTMLPostAlertElement; | ||
|
||
@State() alertId = crypto.randomUUID(); | ||
@State() classes: string; | ||
@State() hasActions: boolean; | ||
@State() hasHeading: boolean; | ||
@State() onDismissButtonClick = () => this.dismiss(); | ||
|
||
/** | ||
* If `true`, a close button (×) is displayed and the alert can be dismissed by the user. | ||
*/ | ||
@Prop() readonly dismissible: boolean = false; | ||
|
||
@Watch('dismissible') | ||
validateDismissible(isDismissible = this.dismissible) { | ||
checkType(isDismissible, 'boolean', 'The post-alert "dismissible" prop should be a boolean.'); | ||
setTimeout(() => this.validateDismissLabel()); | ||
} | ||
|
||
/** | ||
* The label to use for the close button of a dismissible alert. | ||
*/ | ||
@Prop() readonly dismissLabel: string; | ||
|
||
@Watch('dismissLabel') | ||
validateDismissLabel(dismissLabel = this.dismissLabel) { | ||
if (this.dismissible) { | ||
checkNonEmpty(dismissLabel, 'Dismissible post-alert\'s require a "dismiss-label" prop.'); | ||
} | ||
} | ||
|
||
/** | ||
* If `true`, the alert is positioned at the bottom of the window, from edge to edge. | ||
*/ | ||
@Prop() readonly fixed: boolean = false; | ||
|
||
@Watch('fixed') | ||
validateFixed(isFixed = this.fixed) { | ||
checkType(isFixed, 'boolean', 'The post-alert "fixed" prop should be a boolean.'); | ||
} | ||
|
||
/** | ||
* The icon to display in the alert. By default, the icon depends on the alert type. | ||
* | ||
* If `none`, no icon is displayed. | ||
*/ | ||
@Prop() readonly icon: string; | ||
|
||
@Watch('icon') | ||
validateIcon(icon = this.icon) { | ||
checkEmptyOrPattern(icon, /\d{4}|none/, 'The post-alert "icon" prop should be a 4-digits string.'); | ||
} | ||
|
||
/** | ||
* The type of the alert. | ||
*/ | ||
@Prop() readonly type: AlertType = 'primary'; | ||
|
||
@Watch('type') | ||
validateType(type = this.type) { | ||
checkEmptyOrOneOf(type, ALERT_TYPES, `The post-alert requires a type form: ${ALERT_TYPES.join(', ')}`); | ||
} | ||
|
||
/** | ||
* An event emitted when the alert element is dismissed, after the transition. | ||
* It has no payload and only relevant for dismissible alerts. | ||
*/ | ||
@Event() dismissed: EventEmitter<void>; | ||
|
||
connectedCallback() { | ||
this.validateDismissible(); | ||
this.validateFixed(); | ||
this.validateIcon(); | ||
this.validateType(); | ||
} | ||
|
||
componentWillRender() { | ||
this.hasHeading = this.host.querySelectorAll('[slot=heading]').length > 0; | ||
this.hasActions = this.host.querySelectorAll('[slot=actions]').length > 0; | ||
|
||
this.classes = `alert alert-${this.type ?? 'primary'}`; | ||
if (this.dismissible) this.classes += ' alert-dismissible'; | ||
if (this.hasActions) this.classes += ' alert-action'; | ||
if (this.fixed) this.classes += ' alert-fixed-bottom'; | ||
if (this.icon === 'none') this.classes += ' no-icon'; | ||
} | ||
|
||
/** | ||
* Triggers alert dismissal programmatically (same as clicking on the close button (×)). | ||
*/ | ||
@Method() | ||
async dismiss() { | ||
const dismissal = fadeOut(this.host); | ||
|
||
await dismissal.finished; | ||
|
||
this.host.remove(); | ||
this.dismissed.emit(); | ||
} | ||
|
||
render() { | ||
const defaultAlertContent = [ | ||
this.icon && this.icon !== 'none' && ( | ||
<post-icon key={`${this.alertId}-icon`} name={this.icon} /> | ||
), | ||
this.hasHeading && ( | ||
<div key={`${this.alertId}-heading`} class="alert-heading"> | ||
<slot name="heading"/> | ||
</div> | ||
), | ||
<slot key={`${this.alertId}-message`}/> | ||
]; | ||
|
||
const actionAlertContent = [ | ||
<div key={`${this.alertId}-content`} class="alert-content"> | ||
{defaultAlertContent} | ||
</div>, | ||
<div key={`${this.alertId}-buttons`} class="alert-buttons"> | ||
<slot name="actions"/> | ||
</div>, | ||
]; | ||
|
||
return ( | ||
<Host data-version={version}> | ||
<div role="alert" class={this.classes}> | ||
{this.dismissible && ( | ||
<button class="btn-close" onClick={this.onDismissButtonClick}> | ||
<span class="visually-hidden">{this.dismissLabel}</span> | ||
</button> | ||
)} | ||
|
||
{this.hasActions | ||
? actionAlertContent | ||
: defaultAlertContent | ||
} | ||
</div> | ||
</Host> | ||
); | ||
} | ||
|
||
} |
Oops, something went wrong.