@liveblocks/react-ui
Version:
A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.
505 lines (500 loc) • 18.5 kB
JavaScript
"use client";
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var core = require('@liveblocks/core');
var react$1 = require('@liveblocks/react');
var reactSlot = require('@radix-ui/react-slot');
var TooltipPrimitive = require('@radix-ui/react-tooltip');
var react = require('react');
var components = require('../components.cjs');
var Check = require('../icons/Check.cjs');
var Delete = require('../icons/Delete.cjs');
var Ellipsis = require('../icons/Ellipsis.cjs');
var Warning = require('../icons/Warning.cjs');
var overrides = require('../overrides.cjs');
var Timestamp = require('../primitives/Timestamp.cjs');
var shared = require('../shared.cjs');
var classNames = require('../utils/class-names.cjs');
var url = require('../utils/url.cjs');
var Avatar = require('./internal/Avatar.cjs');
var Button = require('./internal/Button.cjs');
var Dropdown = require('./internal/Dropdown.cjs');
var InboxNotificationThread$1 = require('./internal/InboxNotificationThread.cjs');
var List = require('./internal/List.cjs');
var Room = require('./internal/Room.cjs');
var Tooltip = require('./internal/Tooltip.cjs');
var User = require('./internal/User.cjs');
var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
const InboxNotificationLayout = react.forwardRef(
({
inboxNotification,
children,
aside,
title,
date,
unread,
markAsReadOnClick,
onClick,
href,
showActions,
overrides: overrides$1,
components: components$1,
className,
asChild,
...props
}, forwardedRef) => {
const $ = overrides.useOverrides(overrides$1);
const { Anchor } = components.useComponents(components$1);
const Component = asChild ? reactSlot.Slot : Anchor;
const [isMoreActionOpen, setMoreActionOpen] = react.useState(false);
const markInboxNotificationAsRead = react$1.useMarkInboxNotificationAsRead();
const deleteInboxNotification = react$1.useDeleteInboxNotification();
const handleClick = react.useCallback(
(event) => {
onClick?.(event);
const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);
if (unread && shouldMarkAsReadOnClick) {
markInboxNotificationAsRead(inboxNotification.id);
}
},
[
href,
inboxNotification.id,
markAsReadOnClick,
markInboxNotificationAsRead,
onClick,
unread
]
);
const stopPropagation = react.useCallback((event) => {
event.stopPropagation();
}, []);
const preventDefaultAndStopPropagation = react.useCallback(
(event) => {
event.preventDefault();
event.stopPropagation();
},
[]
);
const handleMoreClick = react.useCallback((event) => {
event.preventDefault();
event.stopPropagation();
setMoreActionOpen((open) => !open);
}, []);
const handleMarkAsRead = react.useCallback(() => {
markInboxNotificationAsRead(inboxNotification.id);
}, [inboxNotification.id, markInboxNotificationAsRead]);
const handleDelete = react.useCallback(() => {
deleteInboxNotification(inboxNotification.id);
}, [inboxNotification.id, deleteInboxNotification]);
return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive.TooltipProvider, {
children: /* @__PURE__ */ jsxRuntime.jsxs(Component, {
className: classNames.classNames(
"lb-root lb-inbox-notification",
showActions === "hover" && "lb-inbox-notification:show-actions-hover",
isMoreActionOpen && "lb-inbox-notification:action-open",
className
),
dir: $.dir,
"data-unread": unread ? "" : void 0,
"data-kind": inboxNotification.kind,
onClick: handleClick,
href,
...props,
ref: forwardedRef,
children: [
aside && /* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-aside",
children: aside
}),
/* @__PURE__ */ jsxRuntime.jsxs("div", {
className: "lb-inbox-notification-content",
children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", {
className: "lb-inbox-notification-header",
children: [
/* @__PURE__ */ jsxRuntime.jsx("span", {
className: "lb-inbox-notification-title",
children: title
}),
/* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-details",
children: /* @__PURE__ */ jsxRuntime.jsxs("span", {
className: "lb-inbox-notification-details-labels",
children: [
/* @__PURE__ */ jsxRuntime.jsx(Timestamp.Timestamp, {
locale: $.locale,
date,
className: "lb-date lb-inbox-notification-date"
}),
unread && /* @__PURE__ */ jsxRuntime.jsx("span", {
className: "lb-inbox-notification-unread-indicator",
role: "presentation"
})
]
})
}),
showActions && /* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-actions",
children: /* @__PURE__ */ jsxRuntime.jsx(Dropdown.Dropdown, {
open: isMoreActionOpen,
onOpenChange: setMoreActionOpen,
align: "end",
content: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
unread ? /* @__PURE__ */ jsxRuntime.jsx(Dropdown.DropdownItem, {
onSelect: handleMarkAsRead,
onClick: stopPropagation,
icon: /* @__PURE__ */ jsxRuntime.jsx(Check.CheckIcon, {}),
children: $.INBOX_NOTIFICATION_MARK_AS_READ
}) : null,
/* @__PURE__ */ jsxRuntime.jsx(Dropdown.DropdownItem, {
onSelect: handleDelete,
onClick: stopPropagation,
icon: /* @__PURE__ */ jsxRuntime.jsx(Delete.DeleteIcon, {}),
children: $.INBOX_NOTIFICATION_DELETE
})
]
}),
children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, {
content: $.INBOX_NOTIFICATION_MORE,
children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive.DropdownMenuTrigger, {
asChild: true,
children: /* @__PURE__ */ jsxRuntime.jsx(Button.Button, {
className: "lb-inbox-notification-action",
onClick: handleMoreClick,
onPointerDown: preventDefaultAndStopPropagation,
onPointerUp: preventDefaultAndStopPropagation,
"aria-label": $.INBOX_NOTIFICATION_MORE,
icon: /* @__PURE__ */ jsxRuntime.jsx(Ellipsis.EllipsisIcon, {})
})
})
})
})
})
]
}),
/* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-body",
children
})
]
})
]
})
});
}
);
function InboxNotificationIcon({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx("div", {
className: classNames.classNames("lb-inbox-notification-icon", className),
...props
});
}
function InboxNotificationAvatar({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(Avatar.Avatar, {
className: classNames.classNames("lb-inbox-notification-avatar", className),
...props
});
}
const InboxNotificationThread = react.forwardRef(
({
inboxNotification,
href,
showRoomName = true,
showReactions = true,
showAttachments = true,
showActions = "hover",
overrides: overrides$1,
...props
}, forwardedRef) => {
const $ = overrides.useOverrides(overrides$1);
const thread = react$1.useInboxNotificationThread(inboxNotification.id);
const currentUserId = shared.useCurrentUserId();
const { info } = react$1.useRoomInfo(inboxNotification.roomId);
const contents = react.useMemo(() => {
const contents2 = InboxNotificationThread$1.generateInboxNotificationThreadContents(
inboxNotification,
thread,
currentUserId ?? ""
);
if (contents2.comments.length === 0 || contents2.userIds.length === 0) {
return null;
}
switch (contents2.type) {
case "comments": {
const reversedUserIds = [...contents2.userIds].reverse();
const firstUserId = reversedUserIds[0];
const aside2 = /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationAvatar, {
userId: firstUserId
});
const title2 = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(
/* @__PURE__ */ jsxRuntime.jsx(List.List, {
values: reversedUserIds.map((userId) => /* @__PURE__ */ jsxRuntime.jsx(User.User, {
userId,
replaceSelf: true
}, userId)),
formatRemaining: $.LIST_REMAINING_USERS,
truncate: InboxNotificationThread$1.INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1,
locale: $.locale
}),
showRoomName ? /* @__PURE__ */ jsxRuntime.jsx(Room.Room, {
roomId: thread.roomId
}) : void 0,
reversedUserIds.length
);
const content2 = /* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-comments",
children: contents2.comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationThread$1.InboxNotificationComment, {
comment,
showHeader: contents2.comments.length > 1,
showAttachments,
showReactions,
overrides: overrides$1
}, comment.id))
});
return {
unread: contents2.unread,
date: contents2.date,
aside: aside2,
title: title2,
content: content2,
threadId: thread.id,
commentId: contents2.comments[contents2.comments.length - 1].id
};
}
case "mention": {
const mentionUserId = contents2.userIds[0];
const mentionComment = contents2.comments[0];
const aside2 = /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationAvatar, {
userId: mentionUserId
});
const title2 = $.INBOX_NOTIFICATION_THREAD_MENTION(
/* @__PURE__ */ jsxRuntime.jsx(User.User, {
userId: mentionUserId
}, mentionUserId),
showRoomName ? /* @__PURE__ */ jsxRuntime.jsx(Room.Room, {
roomId: thread.roomId
}) : void 0
);
const content2 = /* @__PURE__ */ jsxRuntime.jsx("div", {
className: "lb-inbox-notification-comments",
children: /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationThread$1.InboxNotificationComment, {
comment: mentionComment,
showHeader: false,
showAttachments,
showReactions,
overrides: overrides$1
}, mentionComment.id)
});
return {
unread: contents2.unread,
date: contents2.date,
aside: aside2,
title: title2,
content: content2,
threadId: thread.id,
commentId: mentionComment.id
};
}
default:
return core.assertNever(
contents2,
"Unexpected thread inbox notification type"
);
}
}, [
$,
currentUserId,
inboxNotification,
overrides$1,
showRoomName,
showAttachments,
showReactions,
thread
]);
const resolvedHref = react.useMemo(() => {
const resolvedHref2 = href ?? info?.url;
return resolvedHref2 ? url.generateURL(resolvedHref2, void 0, contents?.commentId) : void 0;
}, [contents?.commentId, href, info?.url]);
if (!contents) {
return null;
}
const { aside, title, content, date, unread } = contents;
return /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationLayout, {
inboxNotification,
aside,
title,
date,
unread,
overrides: overrides$1,
href: resolvedHref,
showActions,
markAsReadOnClick: false,
...props,
ref: forwardedRef,
children: content
});
}
);
const InboxNotificationTextMention = react.forwardRef(
({
inboxNotification,
showActions = "hover",
showRoomName = true,
href,
overrides: overrides$1,
...props
}, ref) => {
const $ = overrides.useOverrides(overrides$1);
const { info } = react$1.useRoomInfo(inboxNotification.roomId);
const resolvedHref = react.useMemo(() => {
const resolvedHref2 = href ?? info?.url;
return resolvedHref2 ? url.generateURL(resolvedHref2) : void 0;
}, [href, info?.url]);
const unread = react.useMemo(() => {
return !inboxNotification.readAt || inboxNotification.notifiedAt > inboxNotification.readAt;
}, [inboxNotification.notifiedAt, inboxNotification.readAt]);
return /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationLayout, {
inboxNotification,
aside: /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationAvatar, {
userId: inboxNotification.createdBy
}),
title: $.INBOX_NOTIFICATION_TEXT_MENTION(
/* @__PURE__ */ jsxRuntime.jsx(User.User, {
userId: inboxNotification.createdBy
}, inboxNotification.createdBy),
showRoomName ? /* @__PURE__ */ jsxRuntime.jsx(Room.Room, {
roomId: inboxNotification.roomId
}) : void 0
),
date: inboxNotification.notifiedAt,
unread,
overrides: overrides$1,
showActions,
href: resolvedHref,
...props,
ref
});
}
);
const InboxNotificationCustom = react.forwardRef(
({
inboxNotification,
showActions = "hover",
title,
aside,
children,
overrides,
...props
}, forwardedRef) => {
const unread = react.useMemo(() => {
return !inboxNotification.readAt || inboxNotification.notifiedAt > inboxNotification.readAt;
}, [inboxNotification.notifiedAt, inboxNotification.readAt]);
return /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationLayout, {
inboxNotification,
aside,
title,
date: inboxNotification.notifiedAt,
unread,
overrides,
showActions,
...props,
ref: forwardedRef,
children
});
}
);
const InboxNotificationCustomMissing = react.forwardRef(({ inboxNotification, ...props }, forwardedRef) => {
return /* @__PURE__ */ jsxRuntime.jsxs(InboxNotificationCustom, {
inboxNotification,
...props,
title: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [
"Custom notification kind ",
/* @__PURE__ */ jsxRuntime.jsx("code", {
children: inboxNotification.kind
}),
" is not handled"
]
}),
aside: /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationIcon, {
children: /* @__PURE__ */ jsxRuntime.jsx(Warning.WarningIcon, {})
}),
ref: forwardedRef,
"data-missing": "",
children: [
"Notifications of this kind won\u2019t be displayed in production. Use the",
" ",
/* @__PURE__ */ jsxRuntime.jsx("code", {
children: "kinds"
}),
" prop to define how they should be rendered."
]
});
});
const inboxNotificationKindsWarnings = /* @__PURE__ */ new Set();
const InboxNotification = Object.assign(
react.forwardRef(
({ inboxNotification, kinds, ...props }, forwardedRef) => {
switch (inboxNotification.kind) {
case "thread": {
const ResolvedInboxNotificationThread = kinds?.thread ?? InboxNotificationThread;
return /* @__PURE__ */ jsxRuntime.jsx(ResolvedInboxNotificationThread, {
inboxNotification,
...props,
ref: forwardedRef
});
}
case "textMention": {
const ResolvedInboxNotificationTextMention = kinds?.textMention ?? InboxNotificationTextMention;
return /* @__PURE__ */ jsxRuntime.jsx(ResolvedInboxNotificationTextMention, {
inboxNotification,
...props,
ref: forwardedRef
});
}
default: {
const ResolvedInboxNotificationCustom = kinds?.[inboxNotification.kind];
if (!ResolvedInboxNotificationCustom) {
if (process.env.NODE_ENV !== "production") {
if (!inboxNotificationKindsWarnings.has(inboxNotification.kind)) {
inboxNotificationKindsWarnings.add(inboxNotification.kind);
core.console.warn(
`Custom notification kind "${inboxNotification.kind}" is not handled so notifications of this kind will not be displayed in production. Use the kinds prop to define how they should be rendered.`
);
}
return /* @__PURE__ */ jsxRuntime.jsx(InboxNotificationCustomMissing, {
inboxNotification,
...props,
ref: forwardedRef
});
} else {
return null;
}
}
return /* @__PURE__ */ jsxRuntime.jsx(ResolvedInboxNotificationCustom, {
inboxNotification,
...props,
ref: forwardedRef
});
}
}
}
),
{
Thread: InboxNotificationThread,
TextMention: InboxNotificationTextMention,
Custom: InboxNotificationCustom,
Icon: InboxNotificationIcon,
Avatar: InboxNotificationAvatar
}
);
exports.InboxNotification = InboxNotification;
//# sourceMappingURL=InboxNotification.cjs.map