Skip to content

Commit

Permalink
feat(ld-notification): implement notification component
Browse files Browse the repository at this point in the history
  • Loading branch information
borisdiakur committed Aug 4, 2021
1 parent bae42db commit 9511b39
Show file tree
Hide file tree
Showing 4 changed files with 397 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/liquid/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ If you have a suggestion for a new component not listed here, create an [issue o
| [ld-checkbox](./ld-checkbox) | done | done |
| [ld-radio](./ld-radio) | done | done |
| [ld-select](./ld-select) | done | done |
| [ld-option](./ld-option) | done | done |
| [ld-notification](./ld-notification) | done | in progress |
| ld-pattern | done | todo |
92 changes: 92 additions & 0 deletions src/liquid/components/ld-notification/ld-notification.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
.ld-notifcation {
position: fixed;
z-index: 2147483647; /* Highest possible */
display: flex;
justify-content: center;
left: 0;
right: 0;
bottom: 0;
min-width: 20rem;
font: var(--ld-typo-body-s);
}

.ld-notification__item {
position: absolute;
transform-origin: center;
bottom: var(--ld-sp-40);
box-shadow: var(--ld-shadow-sticky);
width: fit-content;
min-width: 19rem;
max-width: calc(90% - 1rem);
border-radius: var(--ld-br-m);
display: flex;
justify-content: space-between;
transition: transform 0.2s ease, opacity 0.2s linear;

&:nth-last-of-type(n + 4) {
display: none;
}

&:nth-last-of-type(n + 2) {
.ld-notification__item-content,
.ld-notification__btn-dismiss {
opacity: 0;
}
}

&:nth-last-of-type(2) {
opacity: 0.75;
transform: scale(0.975) translateY(25%);
}

&:nth-last-of-type(3) {
opacity: 0.5;
transform: scale(0.95) translateY(50%);
}

&:nth-last-of-type(4) {
opacity: 0.25;
transform: scale(0.925) translateY(75%);
}
}

.ld-notification__item--info {
background-color: var(--ld-col-rb-default);
color: var(--ld-col-wht);
}
.ld-notification__item--warn {
background-color: var(--ld-col-vy-default);
color: var(--ld-col-rblck-default);
}
.ld-notification__item--error {
background-color: var(--ld-col-rr-default);
color: var(--ld-col-wht);
}

.ld-notification__item-content,
.ld-notification__btn-dismiss {
transition: opacity 0.2s linear;
}

.ld-notification__item-content {
padding: var(--ld-sp-8) var(--ld-sp-12);
}

.ld-notification__btn-dismiss {
margin-left: var(--ld-sp-16);
align-self: center;
flex-shrink: 0;
border: 0;
border-radius: var(--ld-br-full);
user-select: none;
touch-action: manipulation;
background-color: transparent;
-webkit-touch-callout: none;
cursor: pointer;
padding: 0;
height: 2.5rem;
width: 2.5rem;
display: inline-grid;
place-items: center;
color: inherit;
}
146 changes: 146 additions & 0 deletions src/liquid/components/ld-notification/ld-notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import '../../components' // type definitions for type checks and intelliSense
import { Component, h, Host, Listen, State, Watch } from '@stencil/core'

type Notification = {
type: 'info' | 'warn' | 'error'
content: string
timeout?: number
}

const DEFAULT_NOTIFICATION_TIMEOUT = 6000

@Component({
tag: 'ld-notification',
styleUrl: 'ld-notification.css',
shadow: false,
})
export class LdNotification {
@State() queue: Notification[] = []

@State() dismissTimeout: number

@State() currentNotification?: Notification

@Watch('currentNotification')
updateDismissTimeout() {
clearTimeout(this.dismissTimeout)

if (!this.currentNotification) return
if (this.currentNotification.type === 'error') return
if (this.currentNotification.timeout === 0) return

this.dismissTimeout = window.setTimeout(() => {
this.queue = this.queue.slice(0, -1)
}, this.currentNotification.timeout || DEFAULT_NOTIFICATION_TIMEOUT)
}

@Listen('ldNotification', {
target: 'window',
passive: true,
})
handleNotification(ev: CustomEvent<Notification>) {
ev.stopImmediatePropagation()
const newNotification = ev.detail

// If the same notification is already in queue (same content, same type), ignore this notification.
const inQueue = this.queue.find(
(notification) =>
notification.content === newNotification.content &&
notification.type === newNotification.type
)
if (inQueue) return

// Insert by relevance, whith error notifications being more relevant than non-error notifications.
if (newNotification.type === 'error') {
this.queue = [...this.queue, newNotification]
this.currentNotification = newNotification
return
}

const firstErrorNotificationIndex = this.queue.findIndex(
(notification) => notification.type === 'error'
)
if (firstErrorNotificationIndex === -1) {
this.queue = [...this.queue, newNotification]
this.currentNotification = newNotification
return
}

this.queue.splice(firstErrorNotificationIndex, 0, newNotification)
this.queue = [...this.queue]
}

@Listen('ldNotificationDismiss', {
target: 'window',
passive: true,
})
handleNotificationDismiss() {
this.queue = this.queue.slice(0, -1)
this.currentNotification = this.queue[this.queue.length - 1]
}

@Listen('ldNotificationClear', {
target: 'window',
passive: true,
})
handleNotificationClear() {
this.queue = []
this.currentNotification = undefined
}

disconnectedCallback() {
clearTimeout(this.dismissTimeout)
}

render() {
return (
<Host
class="ld-notifcation"
role="region"
aria-live="polite"
aria-relevant="additions"
>
{this.queue.map((notification, index) => (
<div
class={`ld-notification__item ld-notification__item--${notification.type}`}
key={index}
>
<div
class="ld-notification__item-content"
innerHTML={notification.content}
role={notification.type === 'error' ? 'alert' : 'status'}
></div>
<button
class="ld-notification__btn-dismiss"
onClick={this.handleNotificationDismiss.bind(this)}
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<title>Dismiss</title>
<path
d="M6 6L18 18"
stroke="currentColor"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6 18L18 6"
stroke="currentColor"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
))}
</Host>
)
}
}
Loading

0 comments on commit 9511b39

Please sign in to comment.