hyper/lib/components/notification.tsx

111 lines
3 KiB
TypeScript
Raw Permalink Normal View History

import React, {forwardRef, useEffect, useRef, useState} from 'react';
2023-07-25 09:30:19 -08:00
2023-07-25 01:39:51 -08:00
import type {NotificationProps} from '../../typings/hyper';
2016-07-13 12:44:24 -08:00
const Notification = forwardRef<HTMLDivElement, React.PropsWithChildren<NotificationProps>>((props, ref) => {
const dismissTimer = useRef<NodeJS.Timeout | undefined>(undefined);
const [dismissing, setDismissing] = useState(false);
2016-07-13 12:44:24 -08:00
useEffect(() => {
setDismissTimer();
}, []);
useEffect(() => {
2016-07-13 12:44:24 -08:00
// if we have a timer going and the notification text
2016-07-17 13:05:37 -08:00
// changed we reset the timer
resetDismissTimer();
setDismissing(false);
}, [props.text]);
2016-07-13 12:44:24 -08:00
const handleDismiss = () => {
setDismissing(true);
2019-11-25 07:16:00 -09:00
};
2016-07-13 12:44:24 -08:00
const onElement = (el: HTMLDivElement | null) => {
2016-07-13 12:44:24 -08:00
if (el) {
el.addEventListener('webkitTransitionEnd', () => {
if (dismissing) {
props.onDismiss();
2016-07-13 12:44:24 -08:00
}
});
const {backgroundColor} = props;
2016-07-13 12:44:24 -08:00
if (backgroundColor) {
el.style.setProperty('background-color', backgroundColor, 'important');
2016-07-13 12:44:24 -08:00
}
if (ref) {
if (typeof ref === 'function') ref(el);
else ref.current = el;
}
}
};
const setDismissTimer = () => {
if (typeof props.dismissAfter === 'number') {
dismissTimer.current = setTimeout(() => {
handleDismiss();
}, props.dismissAfter);
2016-07-13 12:44:24 -08:00
}
2019-11-25 07:16:00 -09:00
};
2016-07-13 12:44:24 -08:00
const resetDismissTimer = () => {
clearTimeout(dismissTimer.current);
setDismissTimer();
};
useEffect(() => {
return () => {
clearTimeout(dismissTimer.current);
};
}, []);
2016-07-13 12:44:24 -08:00
const {backgroundColor, color} = props;
const opacity = dismissing ? 0 : 1;
return (
<div ref={onElement} style={{opacity, backgroundColor, color}} className="notification_indicator">
{props.customChildrenBefore}
{props.children || props.text}
{props.userDismissable ? (
<a className="notification_dismissLink" onClick={handleDismiss} style={{color: props.userDismissColor}}>
[x]
</a>
) : null}
{props.customChildren}
2016-07-13 12:44:24 -08:00
<style jsx>{`
.notification_indicator {
display: inline-block;
cursor: default;
-webkit-user-select: none;
background: rgba(255, 255, 255, 0.2);
padding: 8px 14px 9px;
margin-left: 10px;
transition: 150ms opacity ease;
color: #fff;
font-size: 12px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
}
2016-07-13 12:44:24 -08:00
.notification_dismissLink {
position: relative;
left: 4px;
cursor: pointer;
font-weight: 600;
color: currentColor;
transition: font-weight 0.1s ease-in-out;
}
2016-07-13 12:44:24 -08:00
.notification_dismissLink:hover,
.notification_dismissLink:focus {
font-weight: 900;
}
`}</style>
</div>
);
});
2016-07-13 12:44:24 -08:00
Notification.displayName = 'Notification';
export default Notification;