@veracity/vui
Version:
Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.
159 lines (157 loc) • 5.89 kB
JavaScript
import { isReactText, isString } from "../utils/assertion.js";
import { filterUndefined } from "../utils/object.js";
import { cs } from "../utils/styles.js";
import shadows_default from "../theme/foundations/shadows.js";
import { useStyleConfig } from "../core/theme.js";
import styled from "../core/styled.js";
import vui from "../core/vui.js";
import { Box } from "../box/box.js";
import { DismissButton } from "../dismissButton/DismissButton.js";
import { NotificationProvider } from "./context.js";
import { INTENT_ICON_MAP, LOADING_ICON_PROPS, notificationStatusMapping } from "./consts.js";
import { NotificationAction } from "./notificationAction.js";
import { NotificationIcon } from "./notificationIcon.js";
import { NotificationText } from "./notificationText.js";
import { NotificationTitle } from "./notificationTitle.js";
import { DEFAULT_VARIANT, inferNotificationLayout, resolveNotificationAria, resolveNotificationVariant } from "./utils.js";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/notification/notification.tsx
const NotificationContainer = styled(Box)`
${({ $dismissFg }) => $dismissFg && `--vui-dismiss-fg: ${$dismissFg};`}
${`
@keyframes linkSwipe {
from {
background-size: 0 1px;
}
to {
background-size: 100% 1px;
}
}
`}
.vui-notificationText a {
text-decoration: none;
background: linear-gradient(to right, currentColor, currentColor);
background-size: 100% 1px;
background-position: 0 100%;
background-repeat: no-repeat;
padding-bottom: 2px;
}
.vui-notificationText a:hover {
animation: linkSwipe 0.5s ease forwards;
background-size: 100% 1px;
}
${({ $isBanner }) => $isBanner && `
box-shadow: ${shadows_default.md};
position: relative;
width: 100%;
border: none;
`}
`;
/**
* Displays informational content, like text and icon with optional action buttons.
* Handles multiple states, like info, error or loading.
*/
const Notification = vui((props, ref) => {
const { action, align, ariaLive, children, className, icon, intent, isLoading, onClose, role, showDismissButton, size, status, statusMapping, text, title, variant: variantProp = DEFAULT_VARIANT, verticalAlign, ...rest } = props;
const statuses = {
...notificationStatusMapping,
...statusMapping
};
const statusProps = status ? statuses[status] : void 0;
const resolvedVariant = variantProp !== "inline" ? variantProp : statusProps?.variant ?? variantProp;
const intentFromProps = intent ?? statusProps?.intent;
const resolvedIsLoading = isLoading ?? statusProps?.isLoading;
const resolvedIntent = resolvedIsLoading && intentFromProps == null ? "info" : intentFromProps;
const { themeKey, isBanner } = resolveNotificationVariant(resolvedVariant, resolvedIntent);
const layout = inferNotificationLayout({
action,
text,
title,
hasStatus: !!statusProps
});
const aria = resolveNotificationAria({
intent: resolvedIntent,
isLoading: resolvedIsLoading
});
const resolvedRole = role ?? aria.role;
const resolvedAriaLive = ariaLive ?? aria.ariaLive;
const styles = useStyleConfig("Notification", {
variant: themeKey,
size
});
const autoIconProps = resolvedIsLoading ? LOADING_ICON_PROPS : statuses[status ?? ""]?.iconProps ?? (resolvedIntent ? INTENT_ICON_MAP[resolvedIntent] : void 0);
const showIcon = icon !== "";
const iconName = showIcon ? isString(icon) ? icon : !children && autoIconProps?.name || void 0 : void 0;
const context = filterUndefined({
size,
status,
statusMapping,
variant: themeKey,
intent: resolvedIntent,
isLoading: resolvedIsLoading
});
context.layout = layout;
const resolvedAlign = align ?? (verticalAlign === "center" ? "center" : verticalAlign === "flex-start" ? "top" : void 0);
const alignSelf = (resolvedAlign ?? (layout === "one-line" ? "center" : "top")) === "center" ? "center" : "flex-start";
return /* @__PURE__ */ jsx(NotificationProvider, {
value: context,
children: /* @__PURE__ */ jsxs(NotificationContainer, {
borderRadius: "md",
borderWidth: 1,
className: cs("vui-notification", className),
ref,
role: resolvedRole,
"aria-live": resolvedAriaLive,
"data-intent": resolvedIntent,
"data-variant": isBanner ? "banner" : "inline",
"data-layout": layout,
"data-loading": resolvedIsLoading ? "true" : void 0,
"data-align": resolvedAlign,
w: "fit-content",
$dismissFg: styles.container?.["--vui-dismiss-fg"],
$isBanner: isBanner,
...styles.container,
...rest,
children: [
iconName ? /* @__PURE__ */ jsx(Box, {
alignSelf,
...styles.icon,
children: /* @__PURE__ */ jsx(NotificationIcon, {
...autoIconProps,
name: iconName
})
}) : showIcon ? icon : null,
children ?? /* @__PURE__ */ jsxs(Box, {
column: alignSelf !== "center",
flex: 1,
...styles.content,
children: [/* @__PURE__ */ jsxs(NotificationText, { children: [
title ? isReactText(title) ? /* @__PURE__ */ jsx(NotificationTitle, {
display: alignSelf !== "center" ? "block" : "inline",
mb: alignSelf !== "center" && text ? styles.title?.mb : void 0,
text: title
}) : title : null,
title && text && alignSelf === "center" ? " " : null,
text
] }), action ? /* @__PURE__ */ jsx(NotificationAction, { children: action }) : null]
}),
showDismissButton && /* @__PURE__ */ jsx(DismissButton, {
alignSelf,
"aria-label": "Close",
size: "md",
onClick: onClose || (() => {}),
...styles.button
})
]
})
});
});
Notification.Action = NotificationAction;
Notification.Icon = NotificationIcon;
Notification.Text = NotificationText;
Notification.Title = NotificationTitle;
Notification.displayName = "Notification";
//#endregion
export { Notification, Notification as default };
globalThis.__vuiVersion__ = "5.3.1"
//# sourceMappingURL=notification.js.map