UNPKG

@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
"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