@liveblocks/react-ui 2.7.0-beta1 → 2.7.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/InboxNotification.js +4 -1
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotification.mjs +4 -1
- package/dist/components/InboxNotification.mjs.map +1 -1
- package/dist/components/internal/Attachment.js +4 -23
- package/dist/components/internal/Attachment.js.map +1 -1
- package/dist/components/internal/Attachment.mjs +5 -24
- package/dist/components/internal/Attachment.mjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +2 -2
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.mjs +2 -2
- package/dist/components/internal/InboxNotificationThread.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +4 -4
- package/src/styles/index.css +4 -4
- package/styles.css +1 -1
- package/styles.css.map +1 -1
|
@@ -223,6 +223,8 @@ const InboxNotificationThread = React.forwardRef(
|
|
|
223
223
|
key: comment.id,
|
|
224
224
|
comment,
|
|
225
225
|
showHeader: contents.comments.length > 1,
|
|
226
|
+
showAttachments,
|
|
227
|
+
showReactions,
|
|
226
228
|
overrides: overrides$1
|
|
227
229
|
})));
|
|
228
230
|
return {
|
|
@@ -258,7 +260,8 @@ const InboxNotificationThread = React.forwardRef(
|
|
|
258
260
|
comment: mentionComment,
|
|
259
261
|
showHeader: false,
|
|
260
262
|
showAttachments,
|
|
261
|
-
showReactions
|
|
263
|
+
showReactions,
|
|
264
|
+
overrides: overrides$1
|
|
262
265
|
}));
|
|
263
266
|
return {
|
|
264
267
|
unread: contents.unread,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboxNotification.js","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport { assertNever, console } from \"@liveblocks/core\";\nimport {\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { TooltipProvider } from \"@radix-ui/react-tooltip\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { generateURL } from \"../utils/url\";\nimport { Avatar, type AvatarProps } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & InboxNotificationOverrides & CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport type InboxNotificationAvatarProps = AvatarProps;\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={classNames(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n >\n <CheckIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div\n className={classNames(\"lb-inbox-notification-icon\", className)}\n {...props}\n />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={classNames(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Displays a thread inbox notification.\n */\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const thread = useInboxNotificationThread(inboxNotification.id);\n const currentUserId = useCurrentUserId();\n // TODO: If you provide `href` (or plan to), we shouldn't run this hook. We should find a way to conditionally run it.\n // Because of batching and the fact that the same hook will be called within <Room /> in the notification's title,\n // it's not a big deal, the only scenario where it would be superfluous would be if the user provides their own\n // `href` AND disables room names in the title via `showRoomName={false}`.\n const { info } = useRoomInfo(inboxNotification.roomId);\n const { unread, date, aside, title, content, commentId } = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0];\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId, index) => (\n <User\n key={userId}\n userId={userId}\n capitalize={index === 0}\n replaceSelf\n />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1].id,\n };\n }\n\n case \"mention\": {\n const mentionUserId = contents.userIds[0];\n const mentionComment = contents.comments[0];\n\n const aside = <InboxNotificationAvatar userId={mentionUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionUserId} userId={mentionUserId} capitalize />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Add the thread ID and comment ID to the `href`.\n // And use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? generateURL(resolvedHref, undefined, commentId)\n : undefined;\n }, [commentId, href, info?.url]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\n/**\n * Displays a text mention notification kind.\n */\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n capitalize\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\n/**\n * Displays a custom notification kind.\n */\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n {/* TODO: Add link to the docs */}\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered.\n </InboxNotificationCustom>\n );\n});\n\n// Keeps track of which inbox notification kinds it has warned about already.\nconst inboxNotificationKindsWarnings: Set<string> = new Set();\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!inboxNotificationKindsWarnings.has(inboxNotification.kind)) {\n inboxNotificationKindsWarnings.add(inboxNotification.kind);\n // TODO: Add link to the docs\n console.warn(\n `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.`\n );\n }\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n Thread: InboxNotificationThread,\n TextMention: InboxNotificationTextMention,\n Custom: InboxNotificationCustom,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuNA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEK;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEM;AAAc;AACxB;AAAc;AACZ;AAAc;AACZ;AAAe;AACf;AAAc;AACZ;AAAe;AACb;AACW;AACV;AACU;AAGT;AACW;AACL;AAMV;AAAc;AACZ;AACO;AACQ;AACR;AAIC;AACW;AACD;AAER;AAAoB;AAIxB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACD;AACM;AACF;AACC;AAEb;AAAuB;AAQrC;AAAc;AAGrB;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AACG;AAC8D;AACzD;AAGV;AAEA;AAAiC;AAC/B;AAEF;AACE;AACG;AACgE;AAC3D;AAGV;AAKA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AAKA;AACA;AACE;AAAiB;AACf;AACA;AACiB;AAGnB;AAAuB;AAEnB;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAEI;AACM;AACL;AACsB;AACX;AAEd;AACkB;AACgC;AACrD;AACgB;AAAoB;AAAa;AACjC;AAElB;AACG;AAAc;AAEV;AACc;AACb;AACuC;AACvC;AAMR;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC0C;AAC7D;AACF;AAGE;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAAU;AAAuB;AAAyB;AAAC;AAC5C;AAAoB;AAAa;AAEnD;AACG;AAAc;AACZ;AACqB;AACX;AACG;AACZ;AACA;AAKN;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIF;AACE;AAEA;AAEI;AAGN;AACG;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AACf;AACC;AAGP;AAGN;AAKA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACG;AAIL;AAEA;AACE;AAEmD;AAIrD;AACG;AACC;AACQ;AAAkD;AAAW;AAC5D;AACN;AACwB;AACG;AAChB;AACZ;AACgB;AAA+B;AAAa;AAC9D;AACwB;AACxB;AACA;AACA;AACI;AACJ;AACF;AAGN;AAKA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACG;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAGP;AAGN;AAEA;AAIE;AACG;AACC;AACI;AAKF;AAKA;AAEG;AACQ;AAOnB;AAGA;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AACE;AAEA;AAAQ;AACyC;AACjD;AAGF;AACG;AACC;AACI;AACC;AACP;AAIF;AAAO;AACT;AAGF;AACG;AACC;AACI;AACC;AACP;AAEJ;AACF;AACF;AACF;AACA;AACU;AACK;AACL;AACF;AACE;AAEZ;;"}
|
|
1
|
+
{"version":3,"file":"InboxNotification.js","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport { assertNever, console } from \"@liveblocks/core\";\nimport {\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { TooltipProvider } from \"@radix-ui/react-tooltip\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { generateURL } from \"../utils/url\";\nimport { Avatar, type AvatarProps } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & InboxNotificationOverrides & CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport type InboxNotificationAvatarProps = AvatarProps;\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={classNames(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n >\n <CheckIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div\n className={classNames(\"lb-inbox-notification-icon\", className)}\n {...props}\n />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={classNames(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Displays a thread inbox notification.\n */\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const thread = useInboxNotificationThread(inboxNotification.id);\n const currentUserId = useCurrentUserId();\n // TODO: If you provide `href` (or plan to), we shouldn't run this hook. We should find a way to conditionally run it.\n // Because of batching and the fact that the same hook will be called within <Room /> in the notification's title,\n // it's not a big deal, the only scenario where it would be superfluous would be if the user provides their own\n // `href` AND disables room names in the title via `showRoomName={false}`.\n const { info } = useRoomInfo(inboxNotification.roomId);\n const { unread, date, aside, title, content, commentId } = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0];\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId, index) => (\n <User\n key={userId}\n userId={userId}\n capitalize={index === 0}\n replaceSelf\n />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1].id,\n };\n }\n\n case \"mention\": {\n const mentionUserId = contents.userIds[0];\n const mentionComment = contents.comments[0];\n\n const aside = <InboxNotificationAvatar userId={mentionUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionUserId} userId={mentionUserId} capitalize />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Add the thread ID and comment ID to the `href`.\n // And use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? generateURL(resolvedHref, undefined, commentId)\n : undefined;\n }, [commentId, href, info?.url]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\n/**\n * Displays a text mention notification kind.\n */\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n capitalize\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\n/**\n * Displays a custom notification kind.\n */\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n {/* TODO: Add link to the docs */}\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered.\n </InboxNotificationCustom>\n );\n});\n\n// Keeps track of which inbox notification kinds it has warned about already.\nconst inboxNotificationKindsWarnings: Set<string> = new Set();\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!inboxNotificationKindsWarnings.has(inboxNotification.kind)) {\n inboxNotificationKindsWarnings.add(inboxNotification.kind);\n // TODO: Add link to the docs\n console.warn(\n `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.`\n );\n }\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n Thread: InboxNotificationThread,\n TextMention: InboxNotificationTextMention,\n Custom: InboxNotificationCustom,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuNA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEK;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEM;AAAc;AACxB;AAAc;AACZ;AAAc;AACZ;AAAe;AACf;AAAc;AACZ;AAAe;AACb;AACW;AACV;AACU;AAGT;AACW;AACL;AAMV;AAAc;AACZ;AACO;AACQ;AACR;AAIC;AACW;AACD;AAER;AAAoB;AAIxB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACD;AACM;AACF;AACC;AAEb;AAAuB;AAQrC;AAAc;AAGrB;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AACG;AAC8D;AACzD;AAGV;AAEA;AAAiC;AAC/B;AAEF;AACE;AACG;AACgE;AAC3D;AAGV;AAKA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AAKA;AACA;AACE;AAAiB;AACf;AACA;AACiB;AAGnB;AAAuB;AAEnB;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAEI;AACM;AACL;AACsB;AACX;AAEd;AACkB;AACgC;AACrD;AACgB;AAAoB;AAAa;AACjC;AAElB;AACG;AAAc;AAEV;AACc;AACb;AACuC;AACvC;AACA;AACA;AAMR;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC0C;AAC7D;AACF;AAGE;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAAU;AAAuB;AAAyB;AAAC;AAC5C;AAAoB;AAAa;AAEnD;AACG;AAAc;AACZ;AACqB;AACX;AACG;AACZ;AACA;AACA;AAKN;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIF;AACE;AAEA;AAEI;AAGN;AACG;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AACf;AACC;AAGP;AAGN;AAKA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACG;AAIL;AAEA;AACE;AAEmD;AAIrD;AACG;AACC;AACQ;AAAkD;AAAW;AAC5D;AACN;AACwB;AACG;AAChB;AACZ;AACgB;AAA+B;AAAa;AAC9D;AACwB;AACxB;AACA;AACA;AACI;AACJ;AACF;AAGN;AAKA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACG;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAGP;AAGN;AAEA;AAIE;AACG;AACC;AACI;AAKF;AAKA;AAEG;AACQ;AAOnB;AAGA;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AACE;AAEA;AAAQ;AACyC;AACjD;AAGF;AACG;AACC;AACI;AACC;AACP;AAIF;AAAO;AACT;AAGF;AACG;AACC;AACI;AACC;AACP;AAEJ;AACF;AACF;AACF;AACA;AACU;AACK;AACL;AACF;AACE;AAEZ;;"}
|
|
@@ -221,6 +221,8 @@ const InboxNotificationThread = forwardRef(
|
|
|
221
221
|
key: comment.id,
|
|
222
222
|
comment,
|
|
223
223
|
showHeader: contents.comments.length > 1,
|
|
224
|
+
showAttachments,
|
|
225
|
+
showReactions,
|
|
224
226
|
overrides
|
|
225
227
|
})));
|
|
226
228
|
return {
|
|
@@ -256,7 +258,8 @@ const InboxNotificationThread = forwardRef(
|
|
|
256
258
|
comment: mentionComment,
|
|
257
259
|
showHeader: false,
|
|
258
260
|
showAttachments,
|
|
259
|
-
showReactions
|
|
261
|
+
showReactions,
|
|
262
|
+
overrides
|
|
260
263
|
}));
|
|
261
264
|
return {
|
|
262
265
|
unread: contents.unread,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboxNotification.mjs","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport { assertNever, console } from \"@liveblocks/core\";\nimport {\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { TooltipProvider } from \"@radix-ui/react-tooltip\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { generateURL } from \"../utils/url\";\nimport { Avatar, type AvatarProps } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & InboxNotificationOverrides & CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport type InboxNotificationAvatarProps = AvatarProps;\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={classNames(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n >\n <CheckIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div\n className={classNames(\"lb-inbox-notification-icon\", className)}\n {...props}\n />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={classNames(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Displays a thread inbox notification.\n */\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const thread = useInboxNotificationThread(inboxNotification.id);\n const currentUserId = useCurrentUserId();\n // TODO: If you provide `href` (or plan to), we shouldn't run this hook. We should find a way to conditionally run it.\n // Because of batching and the fact that the same hook will be called within <Room /> in the notification's title,\n // it's not a big deal, the only scenario where it would be superfluous would be if the user provides their own\n // `href` AND disables room names in the title via `showRoomName={false}`.\n const { info } = useRoomInfo(inboxNotification.roomId);\n const { unread, date, aside, title, content, commentId } = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0];\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId, index) => (\n <User\n key={userId}\n userId={userId}\n capitalize={index === 0}\n replaceSelf\n />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1].id,\n };\n }\n\n case \"mention\": {\n const mentionUserId = contents.userIds[0];\n const mentionComment = contents.comments[0];\n\n const aside = <InboxNotificationAvatar userId={mentionUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionUserId} userId={mentionUserId} capitalize />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Add the thread ID and comment ID to the `href`.\n // And use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? generateURL(resolvedHref, undefined, commentId)\n : undefined;\n }, [commentId, href, info?.url]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\n/**\n * Displays a text mention notification kind.\n */\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n capitalize\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\n/**\n * Displays a custom notification kind.\n */\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n {/* TODO: Add link to the docs */}\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered.\n </InboxNotificationCustom>\n );\n});\n\n// Keeps track of which inbox notification kinds it has warned about already.\nconst inboxNotificationKindsWarnings: Set<string> = new Set();\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!inboxNotificationKindsWarnings.has(inboxNotification.kind)) {\n inboxNotificationKindsWarnings.add(inboxNotification.kind);\n // TODO: Add link to the docs\n console.warn(\n `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.`\n );\n }\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n Thread: InboxNotificationThread,\n TextMention: InboxNotificationTextMention,\n Custom: InboxNotificationCustom,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAuNA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEK;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEM;AAAc;AACxB;AAAc;AACZ;AAAc;AACZ;AAAe;AACf;AAAc;AACZ;AAAe;AACb;AACW;AACV;AACU;AAGT;AACW;AACL;AAMV;AAAc;AACZ;AACO;AACQ;AACR;AAIC;AACW;AACD;AAER;AAAoB;AAIxB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACD;AACM;AACF;AACC;AAEb;AAAuB;AAQrC;AAAc;AAGrB;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AACG;AAC8D;AACzD;AAGV;AAEA;AAAiC;AAC/B;AAEF;AACE;AACG;AACgE;AAC3D;AAGV;AAKA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AAKA;AACA;AACE;AAAiB;AACf;AACA;AACiB;AAGnB;AAAuB;AAEnB;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAEI;AACM;AACL;AACsB;AACX;AAEd;AACkB;AACgC;AACrD;AACgB;AAAoB;AAAa;AACjC;AAElB;AACG;AAAc;AAEV;AACc;AACb;AACuC;AACvC;AAMR;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC0C;AAC7D;AACF;AAGE;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAAU;AAAuB;AAAyB;AAAC;AAC5C;AAAoB;AAAa;AAEnD;AACG;AAAc;AACZ;AACqB;AACX;AACG;AACZ;AACA;AAKN;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIF;AACE;AAEA;AAEI;AAGN;AACG;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AACf;AACC;AAGP;AAGN;AAKA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACG;AAIL;AAEA;AACE;AAEmD;AAIrD;AACG;AACC;AACQ;AAAkD;AAAW;AAC5D;AACN;AACwB;AACG;AAChB;AACZ;AACgB;AAA+B;AAAa;AAC9D;AACwB;AACxB;AACA;AACA;AACI;AACJ;AACF;AAGN;AAKA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACG;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAGP;AAGN;AAEA;AAIE;AACG;AACC;AACI;AAKF;AAKA;AAEG;AACQ;AAOnB;AAGA;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AACE;AAEA;AAAQ;AACyC;AACjD;AAGF;AACG;AACC;AACI;AACC;AACP;AAIF;AAAO;AACT;AAGF;AACG;AACC;AACI;AACC;AACP;AAEJ;AACF;AACF;AACF;AACA;AACU;AACK;AACL;AACF;AACE;AAEZ;;"}
|
|
1
|
+
{"version":3,"file":"InboxNotification.mjs","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport { assertNever, console } from \"@liveblocks/core\";\nimport {\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { TooltipProvider } from \"@radix-ui/react-tooltip\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { generateURL } from \"../utils/url\";\nimport { Avatar, type AvatarProps } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & InboxNotificationOverrides & CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport type InboxNotificationAvatarProps = AvatarProps;\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={classNames(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n >\n <CheckIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div\n className={classNames(\"lb-inbox-notification-icon\", className)}\n {...props}\n />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={classNames(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Displays a thread inbox notification.\n */\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const thread = useInboxNotificationThread(inboxNotification.id);\n const currentUserId = useCurrentUserId();\n // TODO: If you provide `href` (or plan to), we shouldn't run this hook. We should find a way to conditionally run it.\n // Because of batching and the fact that the same hook will be called within <Room /> in the notification's title,\n // it's not a big deal, the only scenario where it would be superfluous would be if the user provides their own\n // `href` AND disables room names in the title via `showRoomName={false}`.\n const { info } = useRoomInfo(inboxNotification.roomId);\n const { unread, date, aside, title, content, commentId } = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0];\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId, index) => (\n <User\n key={userId}\n userId={userId}\n capitalize={index === 0}\n replaceSelf\n />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1].id,\n };\n }\n\n case \"mention\": {\n const mentionUserId = contents.userIds[0];\n const mentionComment = contents.comments[0];\n\n const aside = <InboxNotificationAvatar userId={mentionUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionUserId} userId={mentionUserId} capitalize />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Add the thread ID and comment ID to the `href`.\n // And use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? generateURL(resolvedHref, undefined, commentId)\n : undefined;\n }, [commentId, href, info?.url]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\n/**\n * Displays a text mention notification kind.\n */\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n capitalize\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\n/**\n * Displays a custom notification kind.\n */\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n {/* TODO: Add link to the docs */}\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered.\n </InboxNotificationCustom>\n );\n});\n\n// Keeps track of which inbox notification kinds it has warned about already.\nconst inboxNotificationKindsWarnings: Set<string> = new Set();\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!inboxNotificationKindsWarnings.has(inboxNotification.kind)) {\n inboxNotificationKindsWarnings.add(inboxNotification.kind);\n // TODO: Add link to the docs\n console.warn(\n `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.`\n );\n }\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n Thread: InboxNotificationThread,\n TextMention: InboxNotificationTextMention,\n Custom: InboxNotificationCustom,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAuNA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEK;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEM;AAAc;AACxB;AAAc;AACZ;AAAc;AACZ;AAAe;AACf;AAAc;AACZ;AAAe;AACb;AACW;AACV;AACU;AAGT;AACW;AACL;AAMV;AAAc;AACZ;AACO;AACQ;AACR;AAIC;AACW;AACD;AAER;AAAoB;AAIxB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACD;AACM;AACF;AACC;AAEb;AAAuB;AAQrC;AAAc;AAGrB;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AACG;AAC8D;AACzD;AAGV;AAEA;AAAiC;AAC/B;AAEF;AACE;AACG;AACgE;AAC3D;AAGV;AAKA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AAKA;AACA;AACE;AAAiB;AACf;AACA;AACiB;AAGnB;AAAuB;AAEnB;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAEI;AACM;AACL;AACsB;AACX;AAEd;AACkB;AACgC;AACrD;AACgB;AAAoB;AAAa;AACjC;AAElB;AACG;AAAc;AAEV;AACc;AACb;AACuC;AACvC;AACA;AACA;AAMR;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC0C;AAC7D;AACF;AAGE;AACA;AAEA;AAAe;AAAgC;AAC/C;AAAgB;AACb;AAAU;AAAuB;AAAyB;AAAC;AAC5C;AAAoB;AAAa;AAEnD;AACG;AAAc;AACZ;AACqB;AACX;AACG;AACZ;AACA;AACA;AAKN;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIF;AACE;AAEA;AAEI;AAGN;AACG;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AACf;AACC;AAGP;AAGN;AAKA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACG;AAIL;AAEA;AACE;AAEmD;AAIrD;AACG;AACC;AACQ;AAAkD;AAAW;AAC5D;AACN;AACwB;AACG;AAChB;AACZ;AACgB;AAA+B;AAAa;AAC9D;AACwB;AACxB;AACA;AACA;AACI;AACJ;AACF;AAGN;AAKA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACG;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAGP;AAGN;AAEA;AAIE;AACG;AACC;AACI;AAKF;AAKA;AAEG;AACQ;AAOnB;AAGA;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACG;AACC;AACI;AACC;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AACE;AAEA;AAAQ;AACyC;AACjD;AAGF;AACG;AACC;AACI;AACC;AACP;AAIF;AAAO;AACT;AAGF;AACG;AACC;AACI;AACC;AACP;AAEJ;AACF;AACF;AACF;AACA;AACU;AACK;AACL;AACF;AACE;AAEZ;;"}
|
|
@@ -25,12 +25,12 @@ function splitFileName(name) {
|
|
|
25
25
|
return { base: match?.[1] ?? name, extension: match?.[2] };
|
|
26
26
|
}
|
|
27
27
|
function getFileAttachmentIconGlyph(mimeType) {
|
|
28
|
-
if (mimeType === "application/zip" || mimeType === "application/x-rar-compressed" || mimeType === "application/x-7z-compressed" || mimeType === "application/x-zip-compressed" || mimeType === "application/x-tar" || mimeType === "application/
|
|
28
|
+
if (mimeType === "application/zip" || mimeType === "application/gzip" || mimeType === "application/vnd.rar" || mimeType === "application/x-rar-compressed" || mimeType === "application/x-7z-compressed" || mimeType === "application/x-zip-compressed" || mimeType === "application/x-tar" || mimeType === "application/x-bzip" || mimeType === "application/x-bzip2") {
|
|
29
29
|
return /* @__PURE__ */ React.createElement("path", {
|
|
30
30
|
d: "M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z"
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
if (mimeType.startsWith("text/")) {
|
|
33
|
+
if (mimeType.startsWith("text/") || mimeType.startsWith("font/") || mimeType.startsWith("application/")) {
|
|
34
34
|
return /* @__PURE__ */ React.createElement("path", {
|
|
35
35
|
d: "M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z"
|
|
36
36
|
});
|
|
@@ -93,21 +93,6 @@ function FileAttachmentImagePreview({ url }) {
|
|
|
93
93
|
onLoad: handleLoad
|
|
94
94
|
})) : null;
|
|
95
95
|
}
|
|
96
|
-
function FileAttachmentLocalImagePreview({
|
|
97
|
-
attachment
|
|
98
|
-
}) {
|
|
99
|
-
const [url, setUrl] = React.useState();
|
|
100
|
-
React.useEffect(() => {
|
|
101
|
-
const url2 = URL.createObjectURL(attachment.file);
|
|
102
|
-
setUrl(url2);
|
|
103
|
-
return () => {
|
|
104
|
-
URL.revokeObjectURL(url2);
|
|
105
|
-
};
|
|
106
|
-
}, [attachment.file]);
|
|
107
|
-
return /* @__PURE__ */ React.createElement(FileAttachmentImagePreview, {
|
|
108
|
-
url
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
96
|
function FileAttachmentRemoteImagePreview({
|
|
112
97
|
attachment
|
|
113
98
|
}) {
|
|
@@ -120,13 +105,9 @@ function FileAttachmentPreview({
|
|
|
120
105
|
attachment
|
|
121
106
|
}) {
|
|
122
107
|
const isInsideRoom = react.useIsInsideRoom();
|
|
123
|
-
const
|
|
108
|
+
const isUploaded = attachment.type === "attachment" || attachment.status === "uploaded";
|
|
124
109
|
if (attachment.mimeType.startsWith("image/") && attachment.size < IMAGE_PREVIEW_MAX_SIZE) {
|
|
125
|
-
if (
|
|
126
|
-
return /* @__PURE__ */ React.createElement(FileAttachmentLocalImagePreview, {
|
|
127
|
-
attachment
|
|
128
|
-
});
|
|
129
|
-
} else if (isInsideRoom) {
|
|
110
|
+
if (isUploaded && isInsideRoom) {
|
|
130
111
|
return /* @__PURE__ */ React.createElement(FileAttachmentRemoteImagePreview, {
|
|
131
112
|
attachment
|
|
132
113
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n CommentAttachment,\n CommentLocalAttachment,\n CommentMixedAttachment,\n} from \"@liveblocks/core\";\nimport { useAttachmentUrl, useIsInsideRoom } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport React, { memo, useCallback, useEffect, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { GlobalOverrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\ninterface FileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n overrides?: Partial<GlobalOverrides>;\n}\n\nconst IMAGE_PREVIEW_MAX_SIZE = 50 * 1024 * 1024; // 50 MB\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getFileAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/gzip\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"text/\")) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst FileAttachmentIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(\n () => getFileAttachmentIconGlyph(mimeType),\n [mimeType]\n );\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction FileAttachmentImagePreview({ url }: { url?: string }) {\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return url ? (\n <div\n className=\"lb-attachment-preview-image\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img src={url} loading=\"lazy\" onLoad={handleLoad} />\n </div>\n ) : null;\n}\n\nfunction FileAttachmentLocalImagePreview({\n attachment,\n}: {\n attachment: CommentLocalAttachment;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const url = URL.createObjectURL(attachment.file);\n\n setUrl(url);\n\n return () => {\n URL.revokeObjectURL(url);\n };\n }, [attachment.file]);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentRemoteImagePreview({\n attachment,\n}: {\n attachment: CommentAttachment;\n}) {\n const { url } = useAttachmentUrl(attachment.id);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentPreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const isInsideRoom = useIsInsideRoom();\n const isLocal = attachment.type === \"localAttachment\";\n\n if (\n attachment.mimeType.startsWith(\"image/\") &&\n attachment.size < IMAGE_PREVIEW_MAX_SIZE\n ) {\n if (isLocal) {\n return <FileAttachmentLocalImagePreview attachment={attachment} />;\n } else if (isInsideRoom) {\n return <FileAttachmentRemoteImagePreview attachment={attachment} />;\n }\n }\n\n return null;\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n className,\n ...props\n}: FileAttachmentProps) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n }, []);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <>\n {!isError ? (\n <FileAttachmentPreview attachment={attachment} />\n ) : null}\n <FileAttachmentIcon mimeType={attachment.mimeType} />\n </>\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">\n {fileExtension}\n </span>\n )}\n </span>\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAkCA;AAEA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAQE;AACG;AAAO;AAAoP;AAIhQ;AACE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAAkB;AACyB;AAChC;AAGX;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEL;AACG;AACQ;AAEX;AACG;AACQ;AAEX;AACG;AACQ;AAGG;AAAY;AAGjC;AAEA;AACE;AAEA;AACE;AAAc;AAGhB;AACG;AACW;AACoB;AAE7B;AAAS;AAAa;AAAe;AAG5C;AAEA;AAAyC;AAEzC;AAGE;AAEA;AACE;AAEA;AAEA;AACE;AAAuB;AACzB;AAGF;AAAQ;AAA2B;AACrC;AAEA;AAA0C;AAE1C;AAGE;AAEA;AAAQ;AAA2B;AACrC;AAEA;AAA+B;AAE/B;AAGE;AACA;AAEA;AAIE;AACE;AAAQ;AAAgC;AAAwB;AAEhE;AAAQ;AAAiC;AAAwB;AACnE;AAGF;AACF;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACE;AAAoC;AAEtC;AAEA;AACA;AAEA;AAEA;AACE;AACE;AAAgB;AAGV;AACN;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEE;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AAGF;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAEpC;AAAc;AAQN;AAAsB;AAExB;AAAwC;AAI9C;AAAc;AACZ;AAAe;AAAuC;AACpD;AAAe;AAEb;AAAe;AAKnB;AAAe;AAAmC;AAKlD;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAQxB;;"}
|
|
1
|
+
{"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useAttachmentUrl, useIsInsideRoom } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport React, { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { GlobalOverrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\ninterface FileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n overrides?: Partial<GlobalOverrides>;\n}\n\nconst IMAGE_PREVIEW_MAX_SIZE = 50 * 1024 * 1024; // 50 MB\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getFileAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst FileAttachmentIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(\n () => getFileAttachmentIconGlyph(mimeType),\n [mimeType]\n );\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction FileAttachmentImagePreview({ url }: { url?: string }) {\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return url ? (\n <div\n className=\"lb-attachment-preview-image\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img src={url} loading=\"lazy\" onLoad={handleLoad} />\n </div>\n ) : null;\n}\n\nfunction FileAttachmentRemoteImagePreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { url } = useAttachmentUrl(attachment.id);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentPreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const isInsideRoom = useIsInsideRoom();\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n if (\n attachment.mimeType.startsWith(\"image/\") &&\n attachment.size < IMAGE_PREVIEW_MAX_SIZE\n ) {\n if (isUploaded && isInsideRoom) {\n return <FileAttachmentRemoteImagePreview attachment={attachment} />;\n }\n }\n\n return null;\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n className,\n ...props\n}: FileAttachmentProps) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n }, []);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <>\n {!isError ? (\n <FileAttachmentPreview attachment={attachment} />\n ) : null}\n <FileAttachmentIcon mimeType={attachment.mimeType} />\n </>\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">\n {fileExtension}\n </span>\n )}\n </span>\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA;AAEA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAWE;AACG;AAAO;AAAoP;AAIhQ;AAKE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAAkB;AACyB;AAChC;AAGX;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEL;AACG;AACQ;AAEX;AACG;AACQ;AAEX;AACG;AACQ;AAGG;AAAY;AAGjC;AAEA;AACE;AAEA;AACE;AAAc;AAGhB;AACG;AACW;AACoB;AAE7B;AAAS;AAAa;AAAe;AAG5C;AAEA;AAA0C;AAE1C;AAGE;AAEA;AAAQ;AAA2B;AACrC;AAEA;AAA+B;AAE/B;AAGE;AACA;AAGA;AAIE;AACE;AAAQ;AAAiC;AAAwB;AACnE;AAGF;AACF;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACE;AAAoC;AAEtC;AAEA;AACA;AAEA;AAEA;AACE;AACE;AAAgB;AAGV;AACN;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEE;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AAGF;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAEpC;AAAc;AAQN;AAAsB;AAExB;AAAwC;AAI9C;AAAc;AACZ;AAAe;AAAuC;AACpD;AAAe;AAEb;AAAe;AAKnB;AAAe;AAAmC;AAKlD;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAQxB;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useIsInsideRoom, useAttachmentUrl } from '@liveblocks/react';
|
|
3
|
-
import React__default, { memo, useMemo, useCallback, useState
|
|
3
|
+
import React__default, { memo, useMemo, useCallback, useState } from 'react';
|
|
4
4
|
import { CrossIcon } from '../../icons/Cross.mjs';
|
|
5
5
|
import { SpinnerIcon } from '../../icons/Spinner.mjs';
|
|
6
6
|
import { WarningIcon } from '../../icons/Warning.mjs';
|
|
@@ -23,12 +23,12 @@ function splitFileName(name) {
|
|
|
23
23
|
return { base: match?.[1] ?? name, extension: match?.[2] };
|
|
24
24
|
}
|
|
25
25
|
function getFileAttachmentIconGlyph(mimeType) {
|
|
26
|
-
if (mimeType === "application/zip" || mimeType === "application/x-rar-compressed" || mimeType === "application/x-7z-compressed" || mimeType === "application/x-zip-compressed" || mimeType === "application/x-tar" || mimeType === "application/
|
|
26
|
+
if (mimeType === "application/zip" || mimeType === "application/gzip" || mimeType === "application/vnd.rar" || mimeType === "application/x-rar-compressed" || mimeType === "application/x-7z-compressed" || mimeType === "application/x-zip-compressed" || mimeType === "application/x-tar" || mimeType === "application/x-bzip" || mimeType === "application/x-bzip2") {
|
|
27
27
|
return /* @__PURE__ */ React__default.createElement("path", {
|
|
28
28
|
d: "M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z"
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
if (mimeType.startsWith("text/")) {
|
|
31
|
+
if (mimeType.startsWith("text/") || mimeType.startsWith("font/") || mimeType.startsWith("application/")) {
|
|
32
32
|
return /* @__PURE__ */ React__default.createElement("path", {
|
|
33
33
|
d: "M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z"
|
|
34
34
|
});
|
|
@@ -91,21 +91,6 @@ function FileAttachmentImagePreview({ url }) {
|
|
|
91
91
|
onLoad: handleLoad
|
|
92
92
|
})) : null;
|
|
93
93
|
}
|
|
94
|
-
function FileAttachmentLocalImagePreview({
|
|
95
|
-
attachment
|
|
96
|
-
}) {
|
|
97
|
-
const [url, setUrl] = useState();
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
const url2 = URL.createObjectURL(attachment.file);
|
|
100
|
-
setUrl(url2);
|
|
101
|
-
return () => {
|
|
102
|
-
URL.revokeObjectURL(url2);
|
|
103
|
-
};
|
|
104
|
-
}, [attachment.file]);
|
|
105
|
-
return /* @__PURE__ */ React__default.createElement(FileAttachmentImagePreview, {
|
|
106
|
-
url
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
94
|
function FileAttachmentRemoteImagePreview({
|
|
110
95
|
attachment
|
|
111
96
|
}) {
|
|
@@ -118,13 +103,9 @@ function FileAttachmentPreview({
|
|
|
118
103
|
attachment
|
|
119
104
|
}) {
|
|
120
105
|
const isInsideRoom = useIsInsideRoom();
|
|
121
|
-
const
|
|
106
|
+
const isUploaded = attachment.type === "attachment" || attachment.status === "uploaded";
|
|
122
107
|
if (attachment.mimeType.startsWith("image/") && attachment.size < IMAGE_PREVIEW_MAX_SIZE) {
|
|
123
|
-
if (
|
|
124
|
-
return /* @__PURE__ */ React__default.createElement(FileAttachmentLocalImagePreview, {
|
|
125
|
-
attachment
|
|
126
|
-
});
|
|
127
|
-
} else if (isInsideRoom) {
|
|
108
|
+
if (isUploaded && isInsideRoom) {
|
|
128
109
|
return /* @__PURE__ */ React__default.createElement(FileAttachmentRemoteImagePreview, {
|
|
129
110
|
attachment
|
|
130
111
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Attachment.mjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n CommentAttachment,\n CommentLocalAttachment,\n CommentMixedAttachment,\n} from \"@liveblocks/core\";\nimport { useAttachmentUrl, useIsInsideRoom } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport React, { memo, useCallback, useEffect, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { GlobalOverrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\ninterface FileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n overrides?: Partial<GlobalOverrides>;\n}\n\nconst IMAGE_PREVIEW_MAX_SIZE = 50 * 1024 * 1024; // 50 MB\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getFileAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/gzip\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"text/\")) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst FileAttachmentIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(\n () => getFileAttachmentIconGlyph(mimeType),\n [mimeType]\n );\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction FileAttachmentImagePreview({ url }: { url?: string }) {\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return url ? (\n <div\n className=\"lb-attachment-preview-image\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img src={url} loading=\"lazy\" onLoad={handleLoad} />\n </div>\n ) : null;\n}\n\nfunction FileAttachmentLocalImagePreview({\n attachment,\n}: {\n attachment: CommentLocalAttachment;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const url = URL.createObjectURL(attachment.file);\n\n setUrl(url);\n\n return () => {\n URL.revokeObjectURL(url);\n };\n }, [attachment.file]);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentRemoteImagePreview({\n attachment,\n}: {\n attachment: CommentAttachment;\n}) {\n const { url } = useAttachmentUrl(attachment.id);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentPreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const isInsideRoom = useIsInsideRoom();\n const isLocal = attachment.type === \"localAttachment\";\n\n if (\n attachment.mimeType.startsWith(\"image/\") &&\n attachment.size < IMAGE_PREVIEW_MAX_SIZE\n ) {\n if (isLocal) {\n return <FileAttachmentLocalImagePreview attachment={attachment} />;\n } else if (isInsideRoom) {\n return <FileAttachmentRemoteImagePreview attachment={attachment} />;\n }\n }\n\n return null;\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n className,\n ...props\n}: FileAttachmentProps) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n }, []);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <>\n {!isError ? (\n <FileAttachmentPreview attachment={attachment} />\n ) : null}\n <FileAttachmentIcon mimeType={attachment.mimeType} />\n </>\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">\n {fileExtension}\n </span>\n )}\n </span>\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAkCA;AAEA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAQE;AACG;AAAO;AAAoP;AAIhQ;AACE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAAkB;AACyB;AAChC;AAGX;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEL;AACG;AACQ;AAEX;AACG;AACQ;AAEX;AACG;AACQ;AAGG;AAAY;AAGjC;AAEA;AACE;AAEA;AACE;AAAc;AAGhB;AACG;AACW;AACoB;AAE7B;AAAS;AAAa;AAAe;AAG5C;AAEA;AAAyC;AAEzC;AAGE;AAEA;AACE;AAEA;AAEA;AACE;AAAuB;AACzB;AAGF;AAAQ;AAA2B;AACrC;AAEA;AAA0C;AAE1C;AAGE;AAEA;AAAQ;AAA2B;AACrC;AAEA;AAA+B;AAE/B;AAGE;AACA;AAEA;AAIE;AACE;AAAQ;AAAgC;AAAwB;AAEhE;AAAQ;AAAiC;AAAwB;AACnE;AAGF;AACF;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACE;AAAoC;AAEtC;AAEA;AACA;AAEA;AAEA;AACE;AACE;AAAgB;AAGV;AACN;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEE;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AAGF;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAEpC;AAAc;AAQN;AAAsB;AAExB;AAAwC;AAI9C;AAAc;AACZ;AAAe;AAAuC;AACpD;AAAe;AAEb;AAAe;AAKnB;AAAe;AAAmC;AAKlD;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAQxB;;"}
|
|
1
|
+
{"version":3,"file":"Attachment.mjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useAttachmentUrl, useIsInsideRoom } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport React, { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { GlobalOverrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\ninterface FileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n overrides?: Partial<GlobalOverrides>;\n}\n\nconst IMAGE_PREVIEW_MAX_SIZE = 50 * 1024 * 1024; // 50 MB\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getFileAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst FileAttachmentIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(\n () => getFileAttachmentIconGlyph(mimeType),\n [mimeType]\n );\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction FileAttachmentImagePreview({ url }: { url?: string }) {\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return url ? (\n <div\n className=\"lb-attachment-preview-image\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img src={url} loading=\"lazy\" onLoad={handleLoad} />\n </div>\n ) : null;\n}\n\nfunction FileAttachmentRemoteImagePreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { url } = useAttachmentUrl(attachment.id);\n\n return <FileAttachmentImagePreview url={url} />;\n}\n\nfunction FileAttachmentPreview({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const isInsideRoom = useIsInsideRoom();\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n if (\n attachment.mimeType.startsWith(\"image/\") &&\n attachment.size < IMAGE_PREVIEW_MAX_SIZE\n ) {\n if (isUploaded && isInsideRoom) {\n return <FileAttachmentRemoteImagePreview attachment={attachment} />;\n }\n }\n\n return null;\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n className,\n ...props\n}: FileAttachmentProps) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n }, []);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <>\n {!isError ? (\n <FileAttachmentPreview attachment={attachment} />\n ) : null}\n <FileAttachmentIcon mimeType={attachment.mimeType} />\n </>\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">\n {fileExtension}\n </span>\n )}\n </span>\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AA8BA;AAEA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAWE;AACG;AAAO;AAAoP;AAIhQ;AAKE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAAkB;AACyB;AAChC;AAGX;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEL;AACG;AACQ;AAEX;AACG;AACQ;AAEX;AACG;AACQ;AAGG;AAAY;AAGjC;AAEA;AACE;AAEA;AACE;AAAc;AAGhB;AACG;AACW;AACoB;AAE7B;AAAS;AAAa;AAAe;AAG5C;AAEA;AAA0C;AAE1C;AAGE;AAEA;AAAQ;AAA2B;AACrC;AAEA;AAA+B;AAE/B;AAGE;AACA;AAGA;AAIE;AACE;AAAQ;AAAiC;AAAwB;AACnE;AAGF;AACF;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACE;AAAoC;AAEtC;AAEA;AACA;AAEA;AAEA;AACE;AACE;AAAgB;AAGV;AACN;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEE;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AAGF;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAEpC;AAAc;AAQN;AAAsB;AAExB;AAAwC;AAI9C;AAAc;AACZ;AAAe;AAAuC;AACpD;AAAe;AAEb;AAAe;AAKnB;AAAe;AAAmC;AAKlD;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAQxB;;"}
|
|
@@ -12,8 +12,8 @@ const INBOX_NOTIFICATION_THREAD_MAX_COMMENTS = 3;
|
|
|
12
12
|
function InboxNotificationComment({
|
|
13
13
|
comment,
|
|
14
14
|
showHeader = true,
|
|
15
|
-
showAttachments,
|
|
16
|
-
showReactions,
|
|
15
|
+
showAttachments = true,
|
|
16
|
+
showReactions = true,
|
|
17
17
|
overrides: overrides$1,
|
|
18
18
|
className,
|
|
19
19
|
...props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboxNotificationThread.js","sources":["../../../src/components/internal/InboxNotificationThread.tsx"],"sourcesContent":["import type {\n BaseMetadata,\n CommentData,\n InboxNotificationThreadData,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { getMentionedIdsFromCommentBody } from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport React from \"react\";\n\nimport {\n type CommentOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../../overrides\";\nimport * as CommentPrimitive from \"../../primitives/Comment\";\nimport { classNames } from \"../../utils/class-names\";\nimport {\n CommentMention,\n CommentNonInteractiveFileAttachment,\n CommentNonInteractiveLink,\n CommentNonInteractiveReaction,\n} from \"../Comment\";\nimport { User } from \"./User\";\n\ntype InboxNotificationThreadCommentsContents = {\n type: \"comments\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\ntype InboxNotificationThreadMentionContents = {\n type: \"mention\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\nexport const INBOX_NOTIFICATION_THREAD_MAX_COMMENTS = 3;\n\ntype InboxNotificationThreadContents =\n | InboxNotificationThreadCommentsContents\n | InboxNotificationThreadMentionContents;\n\ninterface InboxNotificationCommentProps extends ComponentProps<\"div\"> {\n comment: CommentData;\n showHeader?: boolean;\n showAttachments?: boolean;\n showReactions?: boolean;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\nexport function InboxNotificationComment({\n comment,\n showHeader = true,\n showAttachments,\n showReactions,\n overrides,\n className,\n ...props\n}: InboxNotificationCommentProps) {\n const $ = useOverrides(overrides);\n\n return (\n <div\n className={classNames(\n \"lb-root lb-inbox-notification-comment lb-comment\",\n className\n )}\n {...props}\n >\n {showHeader && (\n <div className=\"lb-comment-header\">\n <User className=\"lb-comment-author\" userId={comment.userId} />\n </div>\n )}\n <div className=\"lb-comment-content\">\n {comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: CommentMention,\n Link: CommentNonInteractiveLink,\n }}\n />\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentNonInteractiveReaction\n key={reaction.emoji}\n reaction={reaction}\n overrides={overrides}\n disabled\n />\n ))}\n </div>\n )}\n {showAttachments && comment.attachments.length > 0 ? (\n <div className=\"lb-comment-attachments\">\n {comment.attachments.map((attachment) => (\n <CommentNonInteractiveFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n ))}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Find the last comment with a mention for the given user ID,\n * unless the comment was created by the user themselves.\n */\nfunction findLastCommentWithMentionedId(\n comments: CommentData[],\n mentionedId: string\n) {\n for (let i = comments.length - 1; i >= 0; i--) {\n const comment = comments[i];\n\n if (comment.userId === mentionedId) {\n continue;\n }\n\n if (comment.body) {\n const mentionedIds = getMentionedIdsFromCommentBody(comment.body);\n\n if (mentionedIds.includes(mentionedId)) {\n return comment;\n }\n }\n }\n\n return;\n}\n\nfunction getUserIdsFromComments(comments: CommentData[]) {\n return Array.from(new Set(comments.map((comment) => comment.userId)));\n}\n\nexport function generateInboxNotificationThreadContents(\n inboxNotification: InboxNotificationThreadData,\n thread: ThreadData<BaseMetadata>,\n userId: string\n): InboxNotificationThreadContents {\n const unreadComments = thread.comments.filter((comment) => {\n if (!comment.body) {\n return false;\n }\n\n return inboxNotification.readAt\n ? comment.createdAt > inboxNotification.readAt &&\n comment.createdAt <= inboxNotification.notifiedAt\n : comment.createdAt <= inboxNotification.notifiedAt;\n });\n\n // If the thread is read, show the last comments.\n if (unreadComments.length === 0) {\n const lastComments = thread.comments\n .filter((comment) => comment.body)\n .slice(-INBOX_NOTIFICATION_THREAD_MAX_COMMENTS);\n\n return {\n type: \"comments\",\n unread: false,\n comments: lastComments,\n userIds: getUserIdsFromComments(lastComments),\n date: inboxNotification.notifiedAt,\n };\n }\n\n const commentWithMention = findLastCommentWithMentionedId(\n unreadComments,\n userId\n );\n\n // If the thread contains one or more mentions for the current user, show the last comment with a mention.\n if (commentWithMention) {\n return {\n type: \"mention\",\n unread: true,\n comments: [commentWithMention],\n userIds: [commentWithMention.userId],\n date: commentWithMention.createdAt,\n };\n }\n\n const lastUnreadComments = unreadComments.slice(\n -INBOX_NOTIFICATION_THREAD_MAX_COMMENTS\n );\n\n // Otherwise, show the last unread comments.\n return {\n type: \"comments\",\n unread: true,\n comments: lastUnreadComments,\n userIds: getUserIdsFromComments(unreadComments),\n date: inboxNotification.notifiedAt,\n };\n}\n"],"names":["overrides","useOverrides","classNames","User","CommentPrimitive.Body","CommentMention","CommentNonInteractiveLink","CommentNonInteractiveReaction","CommentNonInteractiveFileAttachment","getMentionedIdsFromCommentBody"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InboxNotificationThread.js","sources":["../../../src/components/internal/InboxNotificationThread.tsx"],"sourcesContent":["import type {\n BaseMetadata,\n CommentData,\n InboxNotificationThreadData,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { getMentionedIdsFromCommentBody } from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport React from \"react\";\n\nimport {\n type CommentOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../../overrides\";\nimport * as CommentPrimitive from \"../../primitives/Comment\";\nimport { classNames } from \"../../utils/class-names\";\nimport {\n CommentMention,\n CommentNonInteractiveFileAttachment,\n CommentNonInteractiveLink,\n CommentNonInteractiveReaction,\n} from \"../Comment\";\nimport { User } from \"./User\";\n\ntype InboxNotificationThreadCommentsContents = {\n type: \"comments\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\ntype InboxNotificationThreadMentionContents = {\n type: \"mention\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\nexport const INBOX_NOTIFICATION_THREAD_MAX_COMMENTS = 3;\n\ntype InboxNotificationThreadContents =\n | InboxNotificationThreadCommentsContents\n | InboxNotificationThreadMentionContents;\n\ninterface InboxNotificationCommentProps extends ComponentProps<\"div\"> {\n comment: CommentData;\n showHeader?: boolean;\n showAttachments?: boolean;\n showReactions?: boolean;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\nexport function InboxNotificationComment({\n comment,\n showHeader = true,\n showAttachments = true,\n showReactions = true,\n overrides,\n className,\n ...props\n}: InboxNotificationCommentProps) {\n const $ = useOverrides(overrides);\n\n return (\n <div\n className={classNames(\n \"lb-root lb-inbox-notification-comment lb-comment\",\n className\n )}\n {...props}\n >\n {showHeader && (\n <div className=\"lb-comment-header\">\n <User className=\"lb-comment-author\" userId={comment.userId} />\n </div>\n )}\n <div className=\"lb-comment-content\">\n {comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: CommentMention,\n Link: CommentNonInteractiveLink,\n }}\n />\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentNonInteractiveReaction\n key={reaction.emoji}\n reaction={reaction}\n overrides={overrides}\n disabled\n />\n ))}\n </div>\n )}\n {showAttachments && comment.attachments.length > 0 ? (\n <div className=\"lb-comment-attachments\">\n {comment.attachments.map((attachment) => (\n <CommentNonInteractiveFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n ))}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Find the last comment with a mention for the given user ID,\n * unless the comment was created by the user themselves.\n */\nfunction findLastCommentWithMentionedId(\n comments: CommentData[],\n mentionedId: string\n) {\n for (let i = comments.length - 1; i >= 0; i--) {\n const comment = comments[i];\n\n if (comment.userId === mentionedId) {\n continue;\n }\n\n if (comment.body) {\n const mentionedIds = getMentionedIdsFromCommentBody(comment.body);\n\n if (mentionedIds.includes(mentionedId)) {\n return comment;\n }\n }\n }\n\n return;\n}\n\nfunction getUserIdsFromComments(comments: CommentData[]) {\n return Array.from(new Set(comments.map((comment) => comment.userId)));\n}\n\nexport function generateInboxNotificationThreadContents(\n inboxNotification: InboxNotificationThreadData,\n thread: ThreadData<BaseMetadata>,\n userId: string\n): InboxNotificationThreadContents {\n const unreadComments = thread.comments.filter((comment) => {\n if (!comment.body) {\n return false;\n }\n\n return inboxNotification.readAt\n ? comment.createdAt > inboxNotification.readAt &&\n comment.createdAt <= inboxNotification.notifiedAt\n : comment.createdAt <= inboxNotification.notifiedAt;\n });\n\n // If the thread is read, show the last comments.\n if (unreadComments.length === 0) {\n const lastComments = thread.comments\n .filter((comment) => comment.body)\n .slice(-INBOX_NOTIFICATION_THREAD_MAX_COMMENTS);\n\n return {\n type: \"comments\",\n unread: false,\n comments: lastComments,\n userIds: getUserIdsFromComments(lastComments),\n date: inboxNotification.notifiedAt,\n };\n }\n\n const commentWithMention = findLastCommentWithMentionedId(\n unreadComments,\n userId\n );\n\n // If the thread contains one or more mentions for the current user, show the last comment with a mention.\n if (commentWithMention) {\n return {\n type: \"mention\",\n unread: true,\n comments: [commentWithMention],\n userIds: [commentWithMention.userId],\n date: commentWithMention.createdAt,\n };\n }\n\n const lastUnreadComments = unreadComments.slice(\n -INBOX_NOTIFICATION_THREAD_MAX_COMMENTS\n );\n\n // Otherwise, show the last unread comments.\n return {\n type: \"comments\",\n unread: true,\n comments: lastUnreadComments,\n userIds: getUserIdsFromComments(unreadComments),\n date: inboxNotification.notifiedAt,\n };\n}\n"],"names":["overrides","useOverrides","classNames","User","CommentPrimitive.Body","CommentMention","CommentNonInteractiveLink","CommentNonInteractiveReaction","CommentNonInteractiveFileAttachment","getMentionedIdsFromCommentBody"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboxNotificationThread.mjs","sources":["../../../src/components/internal/InboxNotificationThread.tsx"],"sourcesContent":["import type {\n BaseMetadata,\n CommentData,\n InboxNotificationThreadData,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { getMentionedIdsFromCommentBody } from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport React from \"react\";\n\nimport {\n type CommentOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../../overrides\";\nimport * as CommentPrimitive from \"../../primitives/Comment\";\nimport { classNames } from \"../../utils/class-names\";\nimport {\n CommentMention,\n CommentNonInteractiveFileAttachment,\n CommentNonInteractiveLink,\n CommentNonInteractiveReaction,\n} from \"../Comment\";\nimport { User } from \"./User\";\n\ntype InboxNotificationThreadCommentsContents = {\n type: \"comments\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\ntype InboxNotificationThreadMentionContents = {\n type: \"mention\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\nexport const INBOX_NOTIFICATION_THREAD_MAX_COMMENTS = 3;\n\ntype InboxNotificationThreadContents =\n | InboxNotificationThreadCommentsContents\n | InboxNotificationThreadMentionContents;\n\ninterface InboxNotificationCommentProps extends ComponentProps<\"div\"> {\n comment: CommentData;\n showHeader?: boolean;\n showAttachments?: boolean;\n showReactions?: boolean;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\nexport function InboxNotificationComment({\n comment,\n showHeader = true,\n showAttachments,\n showReactions,\n overrides,\n className,\n ...props\n}: InboxNotificationCommentProps) {\n const $ = useOverrides(overrides);\n\n return (\n <div\n className={classNames(\n \"lb-root lb-inbox-notification-comment lb-comment\",\n className\n )}\n {...props}\n >\n {showHeader && (\n <div className=\"lb-comment-header\">\n <User className=\"lb-comment-author\" userId={comment.userId} />\n </div>\n )}\n <div className=\"lb-comment-content\">\n {comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: CommentMention,\n Link: CommentNonInteractiveLink,\n }}\n />\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentNonInteractiveReaction\n key={reaction.emoji}\n reaction={reaction}\n overrides={overrides}\n disabled\n />\n ))}\n </div>\n )}\n {showAttachments && comment.attachments.length > 0 ? (\n <div className=\"lb-comment-attachments\">\n {comment.attachments.map((attachment) => (\n <CommentNonInteractiveFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n ))}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Find the last comment with a mention for the given user ID,\n * unless the comment was created by the user themselves.\n */\nfunction findLastCommentWithMentionedId(\n comments: CommentData[],\n mentionedId: string\n) {\n for (let i = comments.length - 1; i >= 0; i--) {\n const comment = comments[i];\n\n if (comment.userId === mentionedId) {\n continue;\n }\n\n if (comment.body) {\n const mentionedIds = getMentionedIdsFromCommentBody(comment.body);\n\n if (mentionedIds.includes(mentionedId)) {\n return comment;\n }\n }\n }\n\n return;\n}\n\nfunction getUserIdsFromComments(comments: CommentData[]) {\n return Array.from(new Set(comments.map((comment) => comment.userId)));\n}\n\nexport function generateInboxNotificationThreadContents(\n inboxNotification: InboxNotificationThreadData,\n thread: ThreadData<BaseMetadata>,\n userId: string\n): InboxNotificationThreadContents {\n const unreadComments = thread.comments.filter((comment) => {\n if (!comment.body) {\n return false;\n }\n\n return inboxNotification.readAt\n ? comment.createdAt > inboxNotification.readAt &&\n comment.createdAt <= inboxNotification.notifiedAt\n : comment.createdAt <= inboxNotification.notifiedAt;\n });\n\n // If the thread is read, show the last comments.\n if (unreadComments.length === 0) {\n const lastComments = thread.comments\n .filter((comment) => comment.body)\n .slice(-INBOX_NOTIFICATION_THREAD_MAX_COMMENTS);\n\n return {\n type: \"comments\",\n unread: false,\n comments: lastComments,\n userIds: getUserIdsFromComments(lastComments),\n date: inboxNotification.notifiedAt,\n };\n }\n\n const commentWithMention = findLastCommentWithMentionedId(\n unreadComments,\n userId\n );\n\n // If the thread contains one or more mentions for the current user, show the last comment with a mention.\n if (commentWithMention) {\n return {\n type: \"mention\",\n unread: true,\n comments: [commentWithMention],\n userIds: [commentWithMention.userId],\n date: commentWithMention.createdAt,\n };\n }\n\n const lastUnreadComments = unreadComments.slice(\n -INBOX_NOTIFICATION_THREAD_MAX_COMMENTS\n );\n\n // Otherwise, show the last unread comments.\n return {\n type: \"comments\",\n unread: true,\n comments: lastUnreadComments,\n userIds: getUserIdsFromComments(unreadComments),\n date: inboxNotification.notifiedAt,\n };\n}\n"],"names":["React","CommentPrimitive.Body"],"mappings":";;;;;;;;AAyCO,MAAM,sCAAyC,GAAA,EAAA;AAc/C,SAAS,wBAAyB,CAAA;AAAA,EACvC,OAAA;AAAA,EACA,UAAa,GAAA,IAAA;AAAA,EACb,
|
|
1
|
+
{"version":3,"file":"InboxNotificationThread.mjs","sources":["../../../src/components/internal/InboxNotificationThread.tsx"],"sourcesContent":["import type {\n BaseMetadata,\n CommentData,\n InboxNotificationThreadData,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { getMentionedIdsFromCommentBody } from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport React from \"react\";\n\nimport {\n type CommentOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../../overrides\";\nimport * as CommentPrimitive from \"../../primitives/Comment\";\nimport { classNames } from \"../../utils/class-names\";\nimport {\n CommentMention,\n CommentNonInteractiveFileAttachment,\n CommentNonInteractiveLink,\n CommentNonInteractiveReaction,\n} from \"../Comment\";\nimport { User } from \"./User\";\n\ntype InboxNotificationThreadCommentsContents = {\n type: \"comments\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\ntype InboxNotificationThreadMentionContents = {\n type: \"mention\";\n unread: boolean;\n comments: CommentData[];\n userIds: string[];\n date: Date;\n};\n\nexport const INBOX_NOTIFICATION_THREAD_MAX_COMMENTS = 3;\n\ntype InboxNotificationThreadContents =\n | InboxNotificationThreadCommentsContents\n | InboxNotificationThreadMentionContents;\n\ninterface InboxNotificationCommentProps extends ComponentProps<\"div\"> {\n comment: CommentData;\n showHeader?: boolean;\n showAttachments?: boolean;\n showReactions?: boolean;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\nexport function InboxNotificationComment({\n comment,\n showHeader = true,\n showAttachments = true,\n showReactions = true,\n overrides,\n className,\n ...props\n}: InboxNotificationCommentProps) {\n const $ = useOverrides(overrides);\n\n return (\n <div\n className={classNames(\n \"lb-root lb-inbox-notification-comment lb-comment\",\n className\n )}\n {...props}\n >\n {showHeader && (\n <div className=\"lb-comment-header\">\n <User className=\"lb-comment-author\" userId={comment.userId} />\n </div>\n )}\n <div className=\"lb-comment-content\">\n {comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: CommentMention,\n Link: CommentNonInteractiveLink,\n }}\n />\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentNonInteractiveReaction\n key={reaction.emoji}\n reaction={reaction}\n overrides={overrides}\n disabled\n />\n ))}\n </div>\n )}\n {showAttachments && comment.attachments.length > 0 ? (\n <div className=\"lb-comment-attachments\">\n {comment.attachments.map((attachment) => (\n <CommentNonInteractiveFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n ))}\n </div>\n ) : null}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Find the last comment with a mention for the given user ID,\n * unless the comment was created by the user themselves.\n */\nfunction findLastCommentWithMentionedId(\n comments: CommentData[],\n mentionedId: string\n) {\n for (let i = comments.length - 1; i >= 0; i--) {\n const comment = comments[i];\n\n if (comment.userId === mentionedId) {\n continue;\n }\n\n if (comment.body) {\n const mentionedIds = getMentionedIdsFromCommentBody(comment.body);\n\n if (mentionedIds.includes(mentionedId)) {\n return comment;\n }\n }\n }\n\n return;\n}\n\nfunction getUserIdsFromComments(comments: CommentData[]) {\n return Array.from(new Set(comments.map((comment) => comment.userId)));\n}\n\nexport function generateInboxNotificationThreadContents(\n inboxNotification: InboxNotificationThreadData,\n thread: ThreadData<BaseMetadata>,\n userId: string\n): InboxNotificationThreadContents {\n const unreadComments = thread.comments.filter((comment) => {\n if (!comment.body) {\n return false;\n }\n\n return inboxNotification.readAt\n ? comment.createdAt > inboxNotification.readAt &&\n comment.createdAt <= inboxNotification.notifiedAt\n : comment.createdAt <= inboxNotification.notifiedAt;\n });\n\n // If the thread is read, show the last comments.\n if (unreadComments.length === 0) {\n const lastComments = thread.comments\n .filter((comment) => comment.body)\n .slice(-INBOX_NOTIFICATION_THREAD_MAX_COMMENTS);\n\n return {\n type: \"comments\",\n unread: false,\n comments: lastComments,\n userIds: getUserIdsFromComments(lastComments),\n date: inboxNotification.notifiedAt,\n };\n }\n\n const commentWithMention = findLastCommentWithMentionedId(\n unreadComments,\n userId\n );\n\n // If the thread contains one or more mentions for the current user, show the last comment with a mention.\n if (commentWithMention) {\n return {\n type: \"mention\",\n unread: true,\n comments: [commentWithMention],\n userIds: [commentWithMention.userId],\n date: commentWithMention.createdAt,\n };\n }\n\n const lastUnreadComments = unreadComments.slice(\n -INBOX_NOTIFICATION_THREAD_MAX_COMMENTS\n );\n\n // Otherwise, show the last unread comments.\n return {\n type: \"comments\",\n unread: true,\n comments: lastUnreadComments,\n userIds: getUserIdsFromComments(unreadComments),\n date: inboxNotification.notifiedAt,\n };\n}\n"],"names":["React","CommentPrimitive.Body"],"mappings":"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"}
|
package/dist/version.js
CHANGED
package/dist/version.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/react-ui",
|
|
3
|
-
"version": "2.7.0-
|
|
3
|
+
"version": "2.7.0-beta2",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@floating-ui/react-dom": "^2.0.8",
|
|
66
|
-
"@liveblocks/client": "2.7.0-
|
|
67
|
-
"@liveblocks/core": "2.7.0-
|
|
68
|
-
"@liveblocks/react": "2.7.0-
|
|
66
|
+
"@liveblocks/client": "2.7.0-beta2",
|
|
67
|
+
"@liveblocks/core": "2.7.0-beta2",
|
|
68
|
+
"@liveblocks/react": "2.7.0-beta2",
|
|
69
69
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
|
70
70
|
"@radix-ui/react-popover": "^1.0.7",
|
|
71
71
|
"@radix-ui/react-slot": "^1.0.2",
|
package/src/styles/index.css
CHANGED
|
@@ -643,6 +643,10 @@
|
|
|
643
643
|
padding: var(--lb-spacing);
|
|
644
644
|
outline: none;
|
|
645
645
|
|
|
646
|
+
:where(.lb-composer-editor-container:has(.lb-composer-attachments)) & {
|
|
647
|
+
padding-block-end: calc(0.25 * var(--lb-spacing));
|
|
648
|
+
}
|
|
649
|
+
|
|
646
650
|
:where([data-placeholder]) {
|
|
647
651
|
color: var(--lb-foreground-moderate);
|
|
648
652
|
}
|
|
@@ -691,10 +695,6 @@
|
|
|
691
695
|
}
|
|
692
696
|
}
|
|
693
697
|
|
|
694
|
-
.lb-composer-editor:where(:has(+ .lb-composer-attachments)) {
|
|
695
|
-
padding-block-end: calc(0.25 * var(--lb-spacing));
|
|
696
|
-
}
|
|
697
|
-
|
|
698
698
|
.lb-composer-attachments {
|
|
699
699
|
padding-inline: var(--lb-spacing);
|
|
700
700
|
padding-block-start: calc(0.75 * var(--lb-spacing));
|
package/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.lb-root{--lb-radius:.5em;--lb-spacing:1em;--lb-accent:#17f;--lb-accent-foreground:#fff;--lb-destructive:#f45;--lb-destructive-foreground:#fff;--lb-background:#fff;--lb-foreground:#111;--lb-icon-size:20px;--lb-icon-weight:1.5px;--lb-avatar-radius:50%;--lb-button-radius:calc(.75*var(--lb-radius));--lb-transition-duration:.1s;--lb-transition-easing:cubic-bezier(.4,0,.2,1);--lb-highlight-shadow:inset 0 0 0 1px #0000001a;--lb-elevation-shadow:0 0 0 1px #0000000a,0 2px 6px #00000014,0 8px 26px #0000001f;--lb-tooltip-shadow:0 2px 4px #00000014,0 4px 12px #0000001f;--lb-accent-contrast:8%;--lb-destructive-contrast:8%;--lb-foreground-contrast:8%;--lb-background-foreground-faint:color-mix(in srgb,var(--lb-foreground),var(--lb-background)calc(100% - var(--lb-foreground-contrast) + ((100% - var(--lb-foreground-contrast))/9)/2));--lb-background-accent-faint:color-mix(in srgb,var(--lb-accent),var(--lb-background)calc(100% - var(--lb-accent-contrast) + ((100% - var(--lb-accent-contrast))/9)/2));--lb-background-accent-subtle:color-mix(in srgb,var(--lb-accent),var(--lb-background)calc(100% - var(--lb-accent-contrast)));--lb-accent-subtle:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - var(--lb-accent-contrast)));--lb-accent-moderate:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 3*((100% - var(--lb-accent-contrast))/9))));--lb-accent-tertiary:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 5*((100% - var(--lb-accent-contrast))/9))));--lb-accent-secondary:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 7*((100% - var(--lb-accent-contrast))/9))));--lb-foreground-subtle:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - var(--lb-foreground-contrast)));--lb-foreground-moderate:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 3*((100% - var(--lb-foreground-contrast))/9))));--lb-foreground-tertiary:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 5*((100% - var(--lb-foreground-contrast))/9))));--lb-foreground-secondary:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 7*((100% - var(--lb-foreground-contrast))/9))));--lb-selection:color-mix(in srgb,var(--lb-accent)40%,transparent);overflow-wrap:break-word;accent-color:var(--lb-accent);-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.lb-root,.lb-root *,.lb-root :before,.lb-root :after{box-sizing:border-box;transition:none var(--lb-transition-duration)var(--lb-transition-easing)}.lb-root:where(:not(.lb-root .lb-root)){--lb-dynamic-background:var(--lb-background)}.lb-icon{--lb-icon-background:var(--lb-dynamic-background);inline-size:var(--lb-icon-size);block-size:var(--lb-icon-size)}.lb-icon *{stroke-width:var(--lb-icon-weight);vector-effect:non-scaling-stroke}.lb-icon-spinner{transform-origin:50%;animation:.75s linear infinite lb-animation-spin}.lb-button{--lb-button-background:var(--lb-dynamic-background);all:unset;box-sizing:inherit;cursor:pointer;-webkit-user-select:none;user-select:none;transition-timing-function:var(--lb-transition-easing);transition-duration:var(--lb-transition-duration);-webkit-tap-highlight-color:transparent;padding:calc(.25*var(--lb-spacing));border-radius:var(--lb-button-radius);background:var(--lb-button-background);color:var(--lb-foreground-moderate);outline:none;justify-content:center;align-items:center;transition-property:background,color,opacity;display:flex;position:relative}.lb-button:after{content:"";border-radius:inherit;pointer-events:none;transition-property:box-shadow;position:absolute;inset:0}.lb-button:where(:focus-visible){z-index:1}.lb-button:where(:focus-visible):after{box-shadow:var(--lb-dynamic-background)0 0 0 2px,var(--lb-accent)0 0 0 4px}.lb-button:where(.lb-button\:non-disableable:disabled){cursor:default}.lb-button:where(:not(.lb-button\:non-disableable):disabled){opacity:.5;cursor:not-allowed}.lb-button:where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){--lb-button-background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary)}.lb-button:where([data-variant=default]:not(:is(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]))){background:0 0}.lb-button:where([data-variant=primary]){--lb-button-background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-button:where([data-variant=primary]):where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){--lb-button-background:var(--lb-accent-secondary);color:var(--lb-accent-foreground)}.lb-button:where([data-variant=outline]){box-shadow:inset 0 0 0 1px var(--lb-foreground-subtle);transition-property:background,color,opacity,box-shadow}.lb-button-icon{--lb-icon-background:var(--lb-button-background)}.lb-dropdown-item-icon{color:var(--lb-foreground-moderate);margin-inline-start:calc(-.125*var(--lb-spacing));margin-inline-end:calc(.375*var(--lb-spacing));transition-property:color}.lb-dropdown-item:where(:is([data-highlighted],[data-selected])) :where(.lb-dropdown-item-icon){color:var(--lb-foreground-tertiary)}.lb-composer-suggestions-list{margin:0;padding:0;list-style:none}.lb-composer-suggestions-list-item{scroll-margin-block:4px}.lb-composer-mention-suggestions{--lb-composer-mention-suggestion-avatar-size:1.25rem}.lb-composer-mention-suggestion{padding:calc(.375*var(--lb-spacing))calc(.625*var(--lb-spacing))}.lb-composer-mention-suggestion-avatar{inline-size:var(--lb-composer-mention-suggestion-avatar-size);margin-inline-start:calc(-.125*var(--lb-spacing));margin-inline-end:calc(.5*var(--lb-spacing));margin-block:calc(.125*var(--lb-spacing));background:var(--lb-foreground-subtle);color:var(--lb-foreground-moderate)}.lb-list{display:contents}@supports (background:-webkit-named-image(i)){.lb-emoji{will-change:transform;transform:scale(.825)}}.lb-emoji-picker{--lb-emoji-picker-padding:6px;--lb-emoji-picker-offset-padding:calc(6px + .375*var(--lb-spacing));color:var(--lb-foreground);flex-direction:column;block-size:360px;display:flex}.lb-emoji-picker-header{border-block-end:1px solid var(--lb-foreground-subtle);flex:none}.lb-emoji-picker-search-container{align-items:center;display:flex;position:relative}.lb-emoji-picker-search{all:unset;box-sizing:inherit;padding:var(--lb-emoji-picker-offset-padding);-webkit-appearance:textfield;appearance:textfield;background:0 0;outline:none;inline-size:100%;padding-inline-start:calc(var(--lb-icon-size) + var(--lb-emoji-picker-offset-padding) + .375*var(--lb-spacing))}.lb-emoji-picker-search::placeholder{color:var(--lb-foreground-moderate)}.lb-emoji-picker-search::-webkit-search-cancel-button{display:none}.lb-emoji-picker-search-icon{color:var(--lb-foreground-moderate);pointer-events:none;position:absolute;inset-inline-start:var(--lb-emoji-picker-offset-padding)}.lb-emoji-picker-content{flex:1;position:relative}.lb-emoji-picker-loading,.lb-emoji-picker-empty,.lb-emoji-picker-error{justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.lb-emoji-picker-loading{color:var(--lb-foreground-moderate)}.lb-emoji-picker-empty,.lb-emoji-picker-error{padding:var(--lb-spacing);color:var(--lb-foreground-tertiary);text-align:center;text-wrap:balance;font-size:.875em}.lb-emoji-picker-category-header{padding:var(--lb-emoji-picker-padding)var(--lb-emoji-picker-offset-padding);background:var(--lb-dynamic-background)}.lb-emoji-picker-category-header-title{color:var(--lb-foreground-tertiary);text-transform:uppercase;font-size:.675em;font-weight:600}.lb-emoji-picker-grid{animation:lb-animation-appear var(--lb-transition-duration)var(--lb-transition-easing)both;position:absolute;inset:0}.lb-emoji-picker-row{padding-inline:var(--lb-emoji-picker-padding);scroll-margin-block-end:var(--lb-emoji-picker-padding);display:flex}.lb-emoji-picker-row:where([data-last]){padding-block-end:var(--lb-emoji-picker-padding)}.lb-emoji-picker-emoji{all:unset;box-sizing:inherit;aspect-ratio:1;padding:calc(.375*var(--lb-spacing));border-radius:calc(var(--lb-radius) - .75*6px);text-align:center;justify-content:center;align-items:center;display:flex;overflow:hidden}.lb-tooltip{--lb-background:#222;--lb-foreground:#fff;--lb-foreground-contrast:10%;min-block-size:calc(calc(1em + 2*.25*var(--lb-spacing)) + 2*5px);padding-inline:calc(.75*var(--lb-spacing));border-radius:var(--lb-radius);background:var(--lb-dynamic-background);color:var(--lb-foreground);box-shadow:var(--lb-tooltip-shadow);overflow-wrap:anywhere;pointer-events:none;align-items:center;max-inline-size:300px;font-size:.75rem;line-height:1;display:flex;position:relative}.lb-tooltip:after{content:"";z-index:1;border-radius:inherit;box-shadow:var(--lb-inset-shadow);pointer-events:none;position:absolute;inset:0}.lb-tooltip\:multiline{padding-block:calc(calc(.625*var(--lb-spacing))*(1/1.5));text-align:center;justify-content:center;line-height:1.5}.lb-tooltip-shortcut{gap:calc(.125*var(--lb-spacing));block-size:calc(1em + 2*.25*var(--lb-spacing));padding-inline:calc(.25*var(--lb-spacing));border-radius:calc(var(--lb-radius) - .625*5px);background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary);text-transform:uppercase;justify-content:center;align-items:center;margin-inline-start:calc(.75*var(--lb-spacing));margin-inline-end:calc(-1*calc(.75*var(--lb-spacing)) + 5px);font-family:inherit;line-height:1;display:flex}.lb-tooltip-shortcut :where(abbr){all:unset}.lb-avatar{aspect-ratio:1;border-radius:var(--lb-avatar-radius);background:var(--lb-foreground-subtle);color:var(--lb-foreground-moderate);justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden;container-type:inline-size}.lb-avatar:where([data-loading]){background:var(--lb-foreground);opacity:.12}.lb-avatar-image{object-fit:cover;block-size:100%;inline-size:100%;position:absolute;inset:0}.lb-avatar-fallback{white-space:nowrap;font-size:35cqi;font-weight:500}@supports not (container-type:inline-size){.lb-avatar-fallback{display:none}}.lb-name:where([data-loading]):before{content:"";vertical-align:middle;border-radius:calc(.5*var(--lb-radius));opacity:.12;-webkit-user-select:none;user-select:none;background:currentColor;block-size:1.75ex;inline-size:8ch;display:inline-block}:is(.lb-avatar,.lb-name):where([data-loading]){animation:8s linear infinite lb-animation-shimmer}:is(.lb-comment-body,.lb-composer-editor){color:var(--lb-foreground-secondary)}:is(.lb-comment-body,.lb-composer-editor) :where(p){margin-block:.25em}:is(.lb-comment-body,.lb-composer-editor) :where(p):where(:first-of-type){margin-block-start:0}:is(.lb-comment-body,.lb-composer-editor) :where(p):where(:last-of-type){margin-block-end:0}:is(.lb-comment-body,.lb-composer-editor) :where(strong){font-weight:600}.lb-comment-mention,.lb-composer-mention{color:var(--lb-accent);-webkit-box-decoration-break:clone;box-decoration-break:clone;font-weight:500}:is(.lb-comment-link,.lb-composer-link){color:var(--lb-foreground);text-decoration-line:underline;-webkit-text-decoration-color:var(--lb-foreground-moderate);text-decoration-color:var(--lb-foreground-moderate);text-underline-offset:2px;outline:none;font-weight:500;transition-property:color,text-decoration-color}:is(.lb-comment-link,.lb-composer-link):where([href]):where(:hover,:focus-visible){color:var(--lb-accent);-webkit-text-decoration-color:var(--lb-accent-moderate);text-decoration-color:var(--lb-accent-moderate)}.lb-comment-mention:where([data-self]),.lb-composer-mention{border-radius:calc(.675*var(--lb-radius));background:var(--lb-accent-subtle);padding:.1em .3em}.lb-composer{background:var(--lb-dynamic-background);color:var(--lb-foreground);transition-property:background;position:relative}.lb-composer-form{margin:0}.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) :where(.lb-button[data-variant=primary]){--lb-button-background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary)}.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) :where(.lb-button[data-variant=primary]):where(:enabled:hover,:enabled:focus-visible){--lb-button-background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-composer-editor{padding:var(--lb-spacing);outline:none}.lb-composer-editor :where([data-placeholder]){color:var(--lb-foreground-moderate)}.lb-composer-mention::selection{background:0 0}.lb-composer-mention ::selection{background:0 0}.lb-composer-mention:where([data-selected]){background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-composer-footer{gap:calc(.75*var(--lb-spacing));block-size:calc(calc(2*.25*var(--lb-spacing) + var(--lb-icon-size)) + var(--lb-spacing));padding:0 var(--lb-spacing)var(--lb-spacing);align-items:center;margin-block-start:calc(-.125*var(--lb-spacing));display:flex}.lb-composer-actions,.lb-composer-editor-actions{gap:calc(.125*var(--lb-spacing));align-items:center;display:flex}.lb-composer-editor-actions{margin-inline-end:auto}.lb-composer-attribution{color:var(--lb-foreground-moderate);outline:none;transition-property:color}.lb-composer-attribution:where(:hover,:focus-visible){color:var(--lb-foreground-tertiary)}.lb-composer-attribution :where(svg){block-size:calc(.75*calc(2*.25*var(--lb-spacing) + var(--lb-icon-size)))}.lb-composer-editor:where(:has(+.lb-composer-attachments)){padding-block-end:calc(.25*var(--lb-spacing))}.lb-composer-attachments{padding-inline:var(--lb-spacing);padding-block-start:calc(.75*var(--lb-spacing));padding-block-end:var(--lb-spacing)}.lb-composer-editor-container:where([data-drop]) *{pointer-events:none}.lb-composer-attachments-drop-area{color:var(--lb-accent);place-content:center;place-items:center;display:flex;position:absolute;inset:0}.lb-composer-attachments-drop-area:before,.lb-composer-attachments-drop-area:after{content:"";inset:calc(.5*var(--lb-spacing));z-index:0;border-radius:calc(.75*var(--lb-radius));position:absolute}.lb-composer-attachments-drop-area:before{opacity:calc(1*var(--lb-accent-contrast));background:currentColor}.lb-composer-attachments-drop-area:after{opacity:calc(2*var(--lb-accent-contrast));border:2px dashed}.lb-composer-attachments-drop-area-label{gap:calc(.25*var(--lb-spacing));padding:calc(.375*var(--lb-spacing))calc(.5*var(--lb-spacing));border-radius:calc(.75*var(--lb-radius));background:var(--lb-accent);color:var(--lb-accent-foreground);pointer-events:none;place-items:center;font-weight:500;display:flex;position:relative}.lb-comment{--lb-comment-avatar-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));padding:var(--lb-spacing);background:var(--lb-dynamic-background);color:var(--lb-foreground);scroll-margin:var(--lb-spacing);font-weight:400;position:relative}.lb-comment:where(:target,[data-target]){--lb-dynamic-background:var(--lb-background-accent-faint)}.lb-comment:where([data-editing]){--lb-dynamic-background:var(--lb-background-foreground-faint)}.lb-comment-header{gap:calc(.75*var(--lb-spacing));block-size:var(--lb-comment-avatar-size);align-items:center;margin-block-end:calc(.75*var(--lb-spacing));display:flex;position:relative}.lb-comment-details{gap:calc(.75*var(--lb-spacing));align-items:center;min-inline-size:0;display:flex}.lb-comment-avatar{inline-size:var(--lb-comment-avatar-size);flex:none}.lb-comment-details-labels{gap:calc(.5*var(--lb-spacing));align-items:baseline;min-inline-size:0;display:flex}.lb-comment-author{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.lb-comment-date{text-overflow:ellipsis;white-space:nowrap;color:var(--lb-foreground-tertiary);font-size:.875em;overflow:hidden}.lb-comment-date-created,.lb-comment-date-edited{display:contents}.lb-comment-actions{gap:calc(.125*var(--lb-spacing));margin-inline-start:auto;display:flex}.lb-comment-composer{margin:calc(-1*var(--lb-spacing));background:unset}.lb-comment-body :where(p span:only-child:empty):before{content:"";-webkit-user-select:none;user-select:none}.lb-comment-attachments{margin-block-start:calc(.75*var(--lb-spacing))}.lb-comment-reactions{gap:calc(.375*var(--lb-spacing));flex-wrap:wrap;margin-block-start:calc(.75*var(--lb-spacing));display:flex}.lb-comment-reaction{gap:calc(.375*var(--lb-spacing));block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));padding-inline:calc(.575*var(--lb-spacing));border-radius:9999px}.lb-comment-reaction:where([data-self]){background:var(--lb-accent-subtle);color:var(--lb-accent-secondary);box-shadow:inset 0 0 0 1px var(--lb-accent-moderate)}.lb-comment-reaction:where([data-self]):where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){color:var(--lb-accent)}.lb-comment-reaction-count{font-variant-numeric:tabular-nums;font-size:.75em;font-weight:500}.lb-comment-reaction-tooltip{max-inline-size:200px}.lb-comment-deleted{color:var(--lb-foreground-tertiary);font-size:.875em}.lb-comment\:indent-content{min-block-size:calc(var(--lb-comment-avatar-size) + 2*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-header){block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));margin-block-end:calc(.25*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-avatar){position:absolute;inset-block-start:0;inset-inline-start:0}.lb-comment\:indent-content :where(.lb-comment-details-labels){margin-inline-start:calc(var(--lb-comment-avatar-size) + .75*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-content){padding-inline-start:calc(var(--lb-comment-avatar-size) + .75*var(--lb-spacing))}.lb-thread{background:var(--lb-dynamic-background);color:var(--lb-foreground);transition-property:background}.lb-thread-comments{z-index:0;flex-direction:column;display:flex;position:relative}.lb-thread-comment{z-index:0;padding-block:calc(.6*var(--lb-spacing));transition-property:background}.lb-thread-comment:where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + var(--lb-spacing))}.lb-thread-comment:where(:first-of-type,[data-editing]){padding-block-start:var(--lb-spacing)}.lb-thread-comment:where(:first-of-type,[data-editing]):where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + 1.5*var(--lb-spacing))}.lb-thread-comment:where(:last-of-type,[data-editing]){padding-block-end:var(--lb-spacing)}.lb-thread-comment:where(:last-of-type,[data-editing]):where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + 1.75*var(--lb-spacing))}.lb-thread-new-indicator{z-index:1;justify-content:center;align-items:center;block-size:0;display:flex;position:relative}.lb-thread-new-indicator:before,.lb-thread-new-indicator:after{content:"";z-index:0;border-block-start:1px solid var(--lb-foreground-subtle);flex:1;block-size:0;transition-property:border}.lb-thread-new-indicator-label{z-index:1;gap:calc(.325*var(--lb-spacing));padding:calc(.25*var(--lb-spacing))var(--lb-spacing);color:var(--lb-accent);text-transform:uppercase;flex:none;align-items:center;font-size:.675em;font-weight:600;display:flex}.lb-thread-new-indicator-label-icon{inline-size:calc(.6*var(--lb-icon-size));block-size:calc(.6*var(--lb-icon-size))}.lb-thread-composer{position:relative}.lb-thread-composer:after{content:"";border-block-start:1px solid var(--lb-foreground-subtle);pointer-events:none;block-size:100%;inline-size:100%;transition-property:border;position:absolute;inset:0}.lb-comment-attachments,.lb-composer-attachments{gap:calc(.75*var(--lb-spacing));grid-template-columns:repeat(auto-fill,minmax(min(100%,200px),1fr));display:grid}.lb-attachment,.lb-attachment-delete{all:unset;box-sizing:inherit;cursor:pointer;-webkit-user-select:none;user-select:none;transition-timing-function:var(--lb-transition-easing);transition-duration:var(--lb-transition-duration);-webkit-tap-highlight-color:transparent;outline:none;transition-property:background,color,opacity;position:relative}.lb-attachment:after,.lb-attachment-delete:after{content:"";border-radius:inherit;pointer-events:none;transition-property:box-shadow;position:absolute;inset:0}.lb-attachment:where(:focus-visible),.lb-attachment-delete:where(:focus-visible){z-index:1}.lb-attachment:where(:focus-visible):after,.lb-attachment-delete:where(:focus-visible):after{box-shadow:var(--lb-dynamic-background)0 0 0 2px,var(--lb-accent)0 0 0 4px}.lb-attachment{border-radius:var(--lb-radius);background:var(--lb-dynamic-background);box-shadow:inset 0 0 0 1px var(--lb-foreground-subtle);inline-size:100%;min-inline-size:0;position:relative}.lb-attachment:where([tabindex="-1"]){cursor:default}.lb-attachment:where(:not([tabindex="-1"])):where(:hover,:focus-visible){background:var(--lb-foreground-subtle)}.lb-attachment-delete{z-index:2;background:var(--lb-foreground-subtle);color:var(--lb-foreground-secondary);box-shadow:0 0 0 2px var(--lb-dynamic-background);opacity:0;border-radius:50%;justify-content:center;align-items:center;block-size:1.1rem;inline-size:1.1rem;display:flex;position:absolute;inset-block-start:-.35rem;inset-inline-end:-.35rem}.lb-attachment-delete:before{content:"";z-index:-1;border-radius:inherit;position:absolute;inset:-4px}.lb-attachment-delete:where(:hover,:focus-visible){background:var(--lb-foreground-secondary);color:var(--lb-dynamic-background)}:where(.lb-attachment:focus-within,.lb-attachment:hover) .lb-attachment-delete{opacity:1}.lb-attachment-delete :where(.lb-icon){inline-size:.75rem}.lb-attachment-name{display:flex}.lb-attachment-name-base,.lb-attachment-description{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lb-attachment-preview{position:relative}.lb-attachment-preview-image{border-radius:inherit;transition-property:opacity}.lb-attachment-preview-image,.lb-attachment-preview-image:after,.lb-attachment-preview-image img{block-size:100%;inline-size:100%;position:absolute;inset:0}.lb-attachment-preview-image img{object-fit:cover}.lb-attachment-preview-image:after{content:"";border-radius:inherit;box-shadow:var(--lb-highlight-shadow);pointer-events:none}.lb-attachment-preview-image:where([data-hidden]){opacity:0}.lb-attachment-icon{color:var(--lb-foreground);flex:none;overflow:visible}.lb-attachment-icon-glyph{fill:var(--lb-foreground-moderate)}.lb-attachment-icon-background{fill:var(--lb-background)}.lb-attachment-icon-fold{fill-opacity:calc(.75*var(--lb-foreground-contrast))}.lb-attachment-icon-shadow{filter:blur(6px);fill-opacity:var(--lb-foreground-contrast)}.lb-file-attachment{gap:calc(.5*var(--lb-spacing));padding:calc(.5*var(--lb-spacing));padding-inline-end:calc(.65*var(--lb-spacing));display:flex}.lb-file-attachment :where(.lb-attachment-preview){aspect-ratio:1;border-radius:calc(.5*var(--lb-radius));background:color-mix(in srgb,transparent,var(--lb-foreground)var(--lb-foreground-contrast));color:var(--lb-foreground-tertiary);flex:none;justify-content:center;align-items:center;inline-size:2.5rem;transition-property:background,color;display:flex;overflow:hidden}.lb-file-attachment:where([data-error]) :where(.lb-attachment-preview){background:var(--lb-destructive);color:var(--lb-destructive-foreground)}.lb-file-attachment :where(.lb-attachment-details){gap:calc(.25*var(--lb-spacing));flex-direction:column;justify-content:center;min-inline-size:0;font-size:.875em;display:flex}.lb-file-attachment :where(.lb-attachment-name),.lb-file-attachment :where(.lb-attachment-description){transition-property:color}.lb-file-attachment :where(.lb-attachment-name){color:var(--lb-foreground-secondary);font-weight:500}.lb-file-attachment :where(.lb-attachment-description){color:var(--lb-foreground-tertiary)}.lb-file-attachment :where(:not([tabindex="-1"])):where(:hover,:focus-visible) :where(.lb-attachment-name){color:var(--lb-foreground)}.lb-file-attachment :where(:not([tabindex="-1"])):where(:hover,:focus-visible) :where(.lb-attachment-description){color:var(--lb-foreground-secondary)}.lb-inbox-notification{--lb-inbox-notification-aside-size:36px;gap:calc(.75*var(--lb-spacing));padding:var(--lb-spacing);background:var(--lb-dynamic-background);color:var(--lb-foreground);-webkit-text-decoration:inherit;text-decoration:inherit;font-weight:400;transition-property:background;display:flex;position:relative;overflow:hidden}.lb-inbox-notification:where([data-missing]){--lb-dynamic-background:var(--lb-background-accent-faint);--lb-accent:var(--lb-destructive)!important;--lb-accent-foreground:var(--lb-destructive-foreground)!important;--lb-accent-contrast:var(--lb-destructive-contrast)!important}.lb-inbox-notification:where([data-unread]){--lb-dynamic-background:var(--lb-background-accent-faint)}.lb-inbox-notification:where([href]){cursor:pointer}.lb-inbox-notification:where([href]):where(:hover,:focus-visible,:focus-within){--lb-dynamic-background:var(--lb-background-foreground-faint)}.lb-inbox-notification:where([href]):where([data-unread]):where(:hover,:focus-visible,:focus-within){--lb-dynamic-background:var(--lb-background-accent-subtle)}.lb-inbox-notification-aside{inline-size:var(--lb-inbox-notification-aside-size);flex:none}.lb-inbox-notification-icon{aspect-ratio:1;background:var(--lb-foreground-subtle);border-radius:50%;justify-content:center;place-items:center;display:flex}.lb-inbox-notification:where([data-missing]) :where(.lb-inbox-notification-icon){background:var(--lb-accent-subtle);color:var(--lb-accent)}.lb-inbox-notification-content{flex:1}.lb-inbox-notification-content,.lb-inbox-notification-body{min-inline-size:0;max-inline-size:100%}.lb-inbox-notification-header{gap:calc(.75*var(--lb-spacing));align-items:center;margin-block-start:calc(.25*var(--lb-spacing));margin-block-end:calc(.5*var(--lb-spacing));display:flex}.lb-inbox-notification-title{min-block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size))}.lb-inbox-notification-title :where(strong,.lb-list,.lb-name){font-weight:500}.lb-inbox-notification-details{block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));flex:none;align-self:start;min-inline-size:0;margin-inline-start:auto}.lb-inbox-notification-details-labels{align-items:baseline;min-inline-size:0;display:flex}.lb-inbox-notification-details-labels:before{content:""}.lb-inbox-notification-actions{gap:calc(.125*var(--lb-spacing));grid-area:actions;align-self:start;display:flex}.lb-inbox-notification-comments{gap:var(--lb-spacing);flex-direction:column;display:flex}.lb-inbox-notification-comment{background:0 0;padding:0}.lb-inbox-notification-comment :where(.lb-comment-header){color:var(--lb-foreground-tertiary);block-size:auto;font-size:.875rem}.lb-inbox-notification-comment :where(.lb-comment-reaction),.lb-inbox-notification-comment :where(.lb-comment-attachment){pointer-events:none}.lb-inbox-notification-date{color:var(--lb-foreground-tertiary);font-size:.875em}.lb-inbox-notification-unread-indicator{background:var(--lb-accent);border-radius:50%;align-self:center;block-size:10px;inline-size:10px;margin-inline-start:calc(.5*var(--lb-spacing))}.lb-inbox-notification-list{margin:0;padding:0;list-style:none}.lb-inbox-notification-list-item:where(:not(:last-of-type)){border-block-end:1px solid var(--lb-foreground-subtle)}.lb-root :where(code){border-radius:calc(.75*var(--lb-radius));background:var(--lb-foreground-subtle);-webkit-box-decoration-break:clone;box-decoration-break:clone;padding:.2em .4em;font-size:85%;line-height:1}.lb-root :where(span:has(code)+span code){border-start-start-radius:0;border-end-start-radius:0;padding-inline-start:0}.lb-root :where(span:has(code):has(+span code) code){border-start-end-radius:0;border-end-end-radius:0;padding-inline-end:0}:where(.lb-root code){font-family:ui-monospace,Menlo,Monaco,Roboto Mono,Cascadia Code,Source Code Pro,Consolas,DejaVu Sans Mono,monospace}.lb-elevation{border-radius:var(--lb-radius);background:var(--lb-dynamic-background);box-shadow:var(--lb-elevation-shadow);position:relative;overflow:hidden}.lb-elevation:after{content:"";z-index:1;border-radius:inherit;box-shadow:var(--lb-inset-shadow);pointer-events:none;position:absolute;inset:0}.lb-dropdown,.lb-composer-suggestions{padding:4px}.lb-dropdown-item,.lb-composer-suggestions-list-item{padding:calc(.25*var(--lb-spacing))calc(.5*var(--lb-spacing));align-items:center;font-size:.875rem;display:flex}.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji{border-radius:calc(var(--lb-radius) - .75*4px);color:var(--lb-foreground-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;transition-property:background,color,opacity}:is(.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji):where([data-highlighted],[data-selected]){background:var(--lb-foreground-subtle);transition-duration:calc(var(--lb-transition-duration)/2)}:is(.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji):where(:disabled,[data-disabled]){opacity:.5;cursor:not-allowed}.lb-dropdown,.lb-composer-suggestions,.lb-tooltip,.lb-emoji-picker{animation-duration:var(--lb-transition-duration);animation-timing-function:var(--lb-transition-easing);will-change:transform,opacity}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip:where([data-state=delayed-open]),.lb-composer-suggestions):where([data-side=top]){animation-name:lb-animation-slide-up}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip:where([data-state=delayed-open]),.lb-composer-suggestions):where([data-side=bottom]){animation-name:lb-animation-slide-down}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip,.lb-composer-suggestions):where([data-state=closed]){animation-name:lb-animation-disappear}@keyframes lb-animation-slide-down{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes lb-animation-slide-up{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes lb-animation-appear{0%{opacity:0}to{opacity:1}}@keyframes lb-animation-disappear{0%{opacity:1}to{opacity:0}}@keyframes lb-animation-shimmer{0%,to{-webkit-mask-image:linear-gradient(90deg,#00000080,#000,#000,#00000080);mask-image:linear-gradient(90deg,#00000080,#000,#000,#00000080);-webkit-mask-size:400% 100%;mask-size:400% 100%}0%{-webkit-mask-position:200% 0;mask-position:200% 0}to{-webkit-mask-position:-200% 0;mask-position:-200% 0}}@keyframes lb-animation-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (hover:hover){.lb-comment:where(.lb-comment\:show-actions-hover) :where(.lb-comment-actions){opacity:0;transition-property:opacity;position:absolute;inset-inline-end:0}.lb-comment:where(.lb-comment\:show-actions-hover):where(:is(:hover,:focus-within,.lb-comment\:action-open)) :where(.lb-comment-actions){opacity:1;position:relative}.lb-thread:where(.lb-thread\:show-actions-hover :is(:hover,:focus-within)) :where(.lb-thread-actions){opacity:1}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-header){grid-template:"title secondary"/1fr max-content;display:grid}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-details){opacity:1;transition-property:opacity}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-actions){opacity:0;transition-property:opacity}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover):where(:is(:hover,:focus-within,.lb-inbox-notification\:action-open)) :where(.lb-inbox-notification-details){opacity:0}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover):where(:is(:hover,:focus-within,.lb-inbox-notification\:action-open)) :where(.lb-inbox-notification-actions){opacity:1}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-details),.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-actions){grid-area:secondary;justify-self:end}}@media (prefers-reduced-motion){.lb-dropdown:where(:not([data-state=closed])),.lb-emoji-picker:where(:not([data-state=closed])),.lb-tooltip:where([data-state=delayed-open]:not([data-state=closed])),.lb-composer-suggestions:where(:not([data-state=closed])){animation-name:lb-animation-appear}}
|
|
1
|
+
.lb-root{--lb-radius:.5em;--lb-spacing:1em;--lb-accent:#17f;--lb-accent-foreground:#fff;--lb-destructive:#f45;--lb-destructive-foreground:#fff;--lb-background:#fff;--lb-foreground:#111;--lb-icon-size:20px;--lb-icon-weight:1.5px;--lb-avatar-radius:50%;--lb-button-radius:calc(.75*var(--lb-radius));--lb-transition-duration:.1s;--lb-transition-easing:cubic-bezier(.4,0,.2,1);--lb-highlight-shadow:inset 0 0 0 1px #0000001a;--lb-elevation-shadow:0 0 0 1px #0000000a,0 2px 6px #00000014,0 8px 26px #0000001f;--lb-tooltip-shadow:0 2px 4px #00000014,0 4px 12px #0000001f;--lb-accent-contrast:8%;--lb-destructive-contrast:8%;--lb-foreground-contrast:8%;--lb-background-foreground-faint:color-mix(in srgb,var(--lb-foreground),var(--lb-background)calc(100% - var(--lb-foreground-contrast) + ((100% - var(--lb-foreground-contrast))/9)/2));--lb-background-accent-faint:color-mix(in srgb,var(--lb-accent),var(--lb-background)calc(100% - var(--lb-accent-contrast) + ((100% - var(--lb-accent-contrast))/9)/2));--lb-background-accent-subtle:color-mix(in srgb,var(--lb-accent),var(--lb-background)calc(100% - var(--lb-accent-contrast)));--lb-accent-subtle:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - var(--lb-accent-contrast)));--lb-accent-moderate:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 3*((100% - var(--lb-accent-contrast))/9))));--lb-accent-tertiary:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 5*((100% - var(--lb-accent-contrast))/9))));--lb-accent-secondary:color-mix(in srgb,var(--lb-accent),var(--lb-dynamic-background)calc(100% - (var(--lb-accent-contrast) + 7*((100% - var(--lb-accent-contrast))/9))));--lb-foreground-subtle:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - var(--lb-foreground-contrast)));--lb-foreground-moderate:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 3*((100% - var(--lb-foreground-contrast))/9))));--lb-foreground-tertiary:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 5*((100% - var(--lb-foreground-contrast))/9))));--lb-foreground-secondary:color-mix(in srgb,var(--lb-foreground),var(--lb-dynamic-background)calc(100% - (var(--lb-foreground-contrast) + 7*((100% - var(--lb-foreground-contrast))/9))));--lb-selection:color-mix(in srgb,var(--lb-accent)40%,transparent);overflow-wrap:break-word;accent-color:var(--lb-accent);-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.lb-root,.lb-root *,.lb-root :before,.lb-root :after{box-sizing:border-box;transition:none var(--lb-transition-duration)var(--lb-transition-easing)}.lb-root:where(:not(.lb-root .lb-root)){--lb-dynamic-background:var(--lb-background)}.lb-icon{--lb-icon-background:var(--lb-dynamic-background);inline-size:var(--lb-icon-size);block-size:var(--lb-icon-size)}.lb-icon *{stroke-width:var(--lb-icon-weight);vector-effect:non-scaling-stroke}.lb-icon-spinner{transform-origin:50%;animation:.75s linear infinite lb-animation-spin}.lb-button{--lb-button-background:var(--lb-dynamic-background);all:unset;box-sizing:inherit;cursor:pointer;-webkit-user-select:none;user-select:none;transition-timing-function:var(--lb-transition-easing);transition-duration:var(--lb-transition-duration);-webkit-tap-highlight-color:transparent;padding:calc(.25*var(--lb-spacing));border-radius:var(--lb-button-radius);background:var(--lb-button-background);color:var(--lb-foreground-moderate);outline:none;justify-content:center;align-items:center;transition-property:background,color,opacity;display:flex;position:relative}.lb-button:after{content:"";border-radius:inherit;pointer-events:none;transition-property:box-shadow;position:absolute;inset:0}.lb-button:where(:focus-visible){z-index:1}.lb-button:where(:focus-visible):after{box-shadow:var(--lb-dynamic-background)0 0 0 2px,var(--lb-accent)0 0 0 4px}.lb-button:where(.lb-button\:non-disableable:disabled){cursor:default}.lb-button:where(:not(.lb-button\:non-disableable):disabled){opacity:.5;cursor:not-allowed}.lb-button:where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){--lb-button-background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary)}.lb-button:where([data-variant=default]:not(:is(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]))){background:0 0}.lb-button:where([data-variant=primary]){--lb-button-background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-button:where([data-variant=primary]):where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){--lb-button-background:var(--lb-accent-secondary);color:var(--lb-accent-foreground)}.lb-button:where([data-variant=outline]){box-shadow:inset 0 0 0 1px var(--lb-foreground-subtle);transition-property:background,color,opacity,box-shadow}.lb-button-icon{--lb-icon-background:var(--lb-button-background)}.lb-dropdown-item-icon{color:var(--lb-foreground-moderate);margin-inline-start:calc(-.125*var(--lb-spacing));margin-inline-end:calc(.375*var(--lb-spacing));transition-property:color}.lb-dropdown-item:where(:is([data-highlighted],[data-selected])) :where(.lb-dropdown-item-icon){color:var(--lb-foreground-tertiary)}.lb-composer-suggestions-list{margin:0;padding:0;list-style:none}.lb-composer-suggestions-list-item{scroll-margin-block:4px}.lb-composer-mention-suggestions{--lb-composer-mention-suggestion-avatar-size:1.25rem}.lb-composer-mention-suggestion{padding:calc(.375*var(--lb-spacing))calc(.625*var(--lb-spacing))}.lb-composer-mention-suggestion-avatar{inline-size:var(--lb-composer-mention-suggestion-avatar-size);margin-inline-start:calc(-.125*var(--lb-spacing));margin-inline-end:calc(.5*var(--lb-spacing));margin-block:calc(.125*var(--lb-spacing));background:var(--lb-foreground-subtle);color:var(--lb-foreground-moderate)}.lb-list{display:contents}@supports (background:-webkit-named-image(i)){.lb-emoji{will-change:transform;transform:scale(.825)}}.lb-emoji-picker{--lb-emoji-picker-padding:6px;--lb-emoji-picker-offset-padding:calc(6px + .375*var(--lb-spacing));color:var(--lb-foreground);flex-direction:column;block-size:360px;display:flex}.lb-emoji-picker-header{border-block-end:1px solid var(--lb-foreground-subtle);flex:none}.lb-emoji-picker-search-container{align-items:center;display:flex;position:relative}.lb-emoji-picker-search{all:unset;box-sizing:inherit;padding:var(--lb-emoji-picker-offset-padding);-webkit-appearance:textfield;appearance:textfield;background:0 0;outline:none;inline-size:100%;padding-inline-start:calc(var(--lb-icon-size) + var(--lb-emoji-picker-offset-padding) + .375*var(--lb-spacing))}.lb-emoji-picker-search::placeholder{color:var(--lb-foreground-moderate)}.lb-emoji-picker-search::-webkit-search-cancel-button{display:none}.lb-emoji-picker-search-icon{color:var(--lb-foreground-moderate);pointer-events:none;position:absolute;inset-inline-start:var(--lb-emoji-picker-offset-padding)}.lb-emoji-picker-content{flex:1;position:relative}.lb-emoji-picker-loading,.lb-emoji-picker-empty,.lb-emoji-picker-error{justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.lb-emoji-picker-loading{color:var(--lb-foreground-moderate)}.lb-emoji-picker-empty,.lb-emoji-picker-error{padding:var(--lb-spacing);color:var(--lb-foreground-tertiary);text-align:center;text-wrap:balance;font-size:.875em}.lb-emoji-picker-category-header{padding:var(--lb-emoji-picker-padding)var(--lb-emoji-picker-offset-padding);background:var(--lb-dynamic-background)}.lb-emoji-picker-category-header-title{color:var(--lb-foreground-tertiary);text-transform:uppercase;font-size:.675em;font-weight:600}.lb-emoji-picker-grid{animation:lb-animation-appear var(--lb-transition-duration)var(--lb-transition-easing)both;position:absolute;inset:0}.lb-emoji-picker-row{padding-inline:var(--lb-emoji-picker-padding);scroll-margin-block-end:var(--lb-emoji-picker-padding);display:flex}.lb-emoji-picker-row:where([data-last]){padding-block-end:var(--lb-emoji-picker-padding)}.lb-emoji-picker-emoji{all:unset;box-sizing:inherit;aspect-ratio:1;padding:calc(.375*var(--lb-spacing));border-radius:calc(var(--lb-radius) - .75*6px);text-align:center;justify-content:center;align-items:center;display:flex;overflow:hidden}.lb-tooltip{--lb-background:#222;--lb-foreground:#fff;--lb-foreground-contrast:10%;min-block-size:calc(calc(1em + 2*.25*var(--lb-spacing)) + 2*5px);padding-inline:calc(.75*var(--lb-spacing));border-radius:var(--lb-radius);background:var(--lb-dynamic-background);color:var(--lb-foreground);box-shadow:var(--lb-tooltip-shadow);overflow-wrap:anywhere;pointer-events:none;align-items:center;max-inline-size:300px;font-size:.75rem;line-height:1;display:flex;position:relative}.lb-tooltip:after{content:"";z-index:1;border-radius:inherit;box-shadow:var(--lb-inset-shadow);pointer-events:none;position:absolute;inset:0}.lb-tooltip\:multiline{padding-block:calc(calc(.625*var(--lb-spacing))*(1/1.5));text-align:center;justify-content:center;line-height:1.5}.lb-tooltip-shortcut{gap:calc(.125*var(--lb-spacing));block-size:calc(1em + 2*.25*var(--lb-spacing));padding-inline:calc(.25*var(--lb-spacing));border-radius:calc(var(--lb-radius) - .625*5px);background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary);text-transform:uppercase;justify-content:center;align-items:center;margin-inline-start:calc(.75*var(--lb-spacing));margin-inline-end:calc(-1*calc(.75*var(--lb-spacing)) + 5px);font-family:inherit;line-height:1;display:flex}.lb-tooltip-shortcut :where(abbr){all:unset}.lb-avatar{aspect-ratio:1;border-radius:var(--lb-avatar-radius);background:var(--lb-foreground-subtle);color:var(--lb-foreground-moderate);justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden;container-type:inline-size}.lb-avatar:where([data-loading]){background:var(--lb-foreground);opacity:.12}.lb-avatar-image{object-fit:cover;block-size:100%;inline-size:100%;position:absolute;inset:0}.lb-avatar-fallback{white-space:nowrap;font-size:35cqi;font-weight:500}@supports not (container-type:inline-size){.lb-avatar-fallback{display:none}}.lb-name:where([data-loading]):before{content:"";vertical-align:middle;border-radius:calc(.5*var(--lb-radius));opacity:.12;-webkit-user-select:none;user-select:none;background:currentColor;block-size:1.75ex;inline-size:8ch;display:inline-block}:is(.lb-avatar,.lb-name):where([data-loading]){animation:8s linear infinite lb-animation-shimmer}:is(.lb-comment-body,.lb-composer-editor){color:var(--lb-foreground-secondary)}:is(.lb-comment-body,.lb-composer-editor) :where(p){margin-block:.25em}:is(.lb-comment-body,.lb-composer-editor) :where(p):where(:first-of-type){margin-block-start:0}:is(.lb-comment-body,.lb-composer-editor) :where(p):where(:last-of-type){margin-block-end:0}:is(.lb-comment-body,.lb-composer-editor) :where(strong){font-weight:600}.lb-comment-mention,.lb-composer-mention{color:var(--lb-accent);-webkit-box-decoration-break:clone;box-decoration-break:clone;font-weight:500}:is(.lb-comment-link,.lb-composer-link){color:var(--lb-foreground);text-decoration-line:underline;-webkit-text-decoration-color:var(--lb-foreground-moderate);text-decoration-color:var(--lb-foreground-moderate);text-underline-offset:2px;outline:none;font-weight:500;transition-property:color,text-decoration-color}:is(.lb-comment-link,.lb-composer-link):where([href]):where(:hover,:focus-visible){color:var(--lb-accent);-webkit-text-decoration-color:var(--lb-accent-moderate);text-decoration-color:var(--lb-accent-moderate)}.lb-comment-mention:where([data-self]),.lb-composer-mention{border-radius:calc(.675*var(--lb-radius));background:var(--lb-accent-subtle);padding:.1em .3em}.lb-composer{background:var(--lb-dynamic-background);color:var(--lb-foreground);transition-property:background;position:relative}.lb-composer-form{margin:0}.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) :where(.lb-button[data-variant=primary]){--lb-button-background:var(--lb-foreground-subtle);color:var(--lb-foreground-tertiary)}.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) :where(.lb-button[data-variant=primary]):where(:enabled:hover,:enabled:focus-visible){--lb-button-background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-composer-editor{padding:var(--lb-spacing);outline:none}:where(.lb-composer-editor-container:has(.lb-composer-attachments)) .lb-composer-editor{padding-block-end:calc(.25*var(--lb-spacing))}.lb-composer-editor :where([data-placeholder]){color:var(--lb-foreground-moderate)}.lb-composer-mention::selection{background:0 0}.lb-composer-mention ::selection{background:0 0}.lb-composer-mention:where([data-selected]){background:var(--lb-accent);color:var(--lb-accent-foreground)}.lb-composer-footer{gap:calc(.75*var(--lb-spacing));block-size:calc(calc(2*.25*var(--lb-spacing) + var(--lb-icon-size)) + var(--lb-spacing));padding:0 var(--lb-spacing)var(--lb-spacing);align-items:center;margin-block-start:calc(-.125*var(--lb-spacing));display:flex}.lb-composer-actions,.lb-composer-editor-actions{gap:calc(.125*var(--lb-spacing));align-items:center;display:flex}.lb-composer-editor-actions{margin-inline-end:auto}.lb-composer-attribution{color:var(--lb-foreground-moderate);outline:none;transition-property:color}.lb-composer-attribution:where(:hover,:focus-visible){color:var(--lb-foreground-tertiary)}.lb-composer-attribution :where(svg){block-size:calc(.75*calc(2*.25*var(--lb-spacing) + var(--lb-icon-size)))}.lb-composer-attachments{padding-inline:var(--lb-spacing);padding-block-start:calc(.75*var(--lb-spacing));padding-block-end:var(--lb-spacing)}.lb-composer-editor-container:where([data-drop]) *{pointer-events:none}.lb-composer-attachments-drop-area{color:var(--lb-accent);place-content:center;place-items:center;display:flex;position:absolute;inset:0}.lb-composer-attachments-drop-area:before,.lb-composer-attachments-drop-area:after{content:"";inset:calc(.5*var(--lb-spacing));z-index:0;border-radius:calc(.75*var(--lb-radius));position:absolute}.lb-composer-attachments-drop-area:before{opacity:calc(1*var(--lb-accent-contrast));background:currentColor}.lb-composer-attachments-drop-area:after{opacity:calc(2*var(--lb-accent-contrast));border:2px dashed}.lb-composer-attachments-drop-area-label{gap:calc(.25*var(--lb-spacing));padding:calc(.375*var(--lb-spacing))calc(.5*var(--lb-spacing));border-radius:calc(.75*var(--lb-radius));background:var(--lb-accent);color:var(--lb-accent-foreground);pointer-events:none;place-items:center;font-weight:500;display:flex;position:relative}.lb-comment{--lb-comment-avatar-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));padding:var(--lb-spacing);background:var(--lb-dynamic-background);color:var(--lb-foreground);scroll-margin:var(--lb-spacing);font-weight:400;position:relative}.lb-comment:where(:target,[data-target]){--lb-dynamic-background:var(--lb-background-accent-faint)}.lb-comment:where([data-editing]){--lb-dynamic-background:var(--lb-background-foreground-faint)}.lb-comment-header{gap:calc(.75*var(--lb-spacing));block-size:var(--lb-comment-avatar-size);align-items:center;margin-block-end:calc(.75*var(--lb-spacing));display:flex;position:relative}.lb-comment-details{gap:calc(.75*var(--lb-spacing));align-items:center;min-inline-size:0;display:flex}.lb-comment-avatar{inline-size:var(--lb-comment-avatar-size);flex:none}.lb-comment-details-labels{gap:calc(.5*var(--lb-spacing));align-items:baseline;min-inline-size:0;display:flex}.lb-comment-author{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.lb-comment-date{text-overflow:ellipsis;white-space:nowrap;color:var(--lb-foreground-tertiary);font-size:.875em;overflow:hidden}.lb-comment-date-created,.lb-comment-date-edited{display:contents}.lb-comment-actions{gap:calc(.125*var(--lb-spacing));margin-inline-start:auto;display:flex}.lb-comment-composer{margin:calc(-1*var(--lb-spacing));background:unset}.lb-comment-body :where(p span:only-child:empty):before{content:"";-webkit-user-select:none;user-select:none}.lb-comment-attachments{margin-block-start:calc(.75*var(--lb-spacing))}.lb-comment-reactions{gap:calc(.375*var(--lb-spacing));flex-wrap:wrap;margin-block-start:calc(.75*var(--lb-spacing));display:flex}.lb-comment-reaction{gap:calc(.375*var(--lb-spacing));block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));padding-inline:calc(.575*var(--lb-spacing));border-radius:9999px}.lb-comment-reaction:where([data-self]){background:var(--lb-accent-subtle);color:var(--lb-accent-secondary);box-shadow:inset 0 0 0 1px var(--lb-accent-moderate)}.lb-comment-reaction:where([data-self]):where(:enabled:hover,:enabled:focus-visible,[aria-expanded=true],[aria-selected=true]){color:var(--lb-accent)}.lb-comment-reaction-count{font-variant-numeric:tabular-nums;font-size:.75em;font-weight:500}.lb-comment-reaction-tooltip{max-inline-size:200px}.lb-comment-deleted{color:var(--lb-foreground-tertiary);font-size:.875em}.lb-comment\:indent-content{min-block-size:calc(var(--lb-comment-avatar-size) + 2*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-header){block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));margin-block-end:calc(.25*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-avatar){position:absolute;inset-block-start:0;inset-inline-start:0}.lb-comment\:indent-content :where(.lb-comment-details-labels){margin-inline-start:calc(var(--lb-comment-avatar-size) + .75*var(--lb-spacing))}.lb-comment\:indent-content :where(.lb-comment-content){padding-inline-start:calc(var(--lb-comment-avatar-size) + .75*var(--lb-spacing))}.lb-thread{background:var(--lb-dynamic-background);color:var(--lb-foreground);transition-property:background}.lb-thread-comments{z-index:0;flex-direction:column;display:flex;position:relative}.lb-thread-comment{z-index:0;padding-block:calc(.6*var(--lb-spacing));transition-property:background}.lb-thread-comment:where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + var(--lb-spacing))}.lb-thread-comment:where(:first-of-type,[data-editing]){padding-block-start:var(--lb-spacing)}.lb-thread-comment:where(:first-of-type,[data-editing]):where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + 1.5*var(--lb-spacing))}.lb-thread-comment:where(:last-of-type,[data-editing]){padding-block-end:var(--lb-spacing)}.lb-thread-comment:where(:last-of-type,[data-editing]):where(.lb-comment\:indent-content){min-block-size:calc(var(--lb-comment-avatar-size) + 1.75*var(--lb-spacing))}.lb-thread-new-indicator{z-index:1;justify-content:center;align-items:center;block-size:0;display:flex;position:relative}.lb-thread-new-indicator:before,.lb-thread-new-indicator:after{content:"";z-index:0;border-block-start:1px solid var(--lb-foreground-subtle);flex:1;block-size:0;transition-property:border}.lb-thread-new-indicator-label{z-index:1;gap:calc(.325*var(--lb-spacing));padding:calc(.25*var(--lb-spacing))var(--lb-spacing);color:var(--lb-accent);text-transform:uppercase;flex:none;align-items:center;font-size:.675em;font-weight:600;display:flex}.lb-thread-new-indicator-label-icon{inline-size:calc(.6*var(--lb-icon-size));block-size:calc(.6*var(--lb-icon-size))}.lb-thread-composer{position:relative}.lb-thread-composer:after{content:"";border-block-start:1px solid var(--lb-foreground-subtle);pointer-events:none;block-size:100%;inline-size:100%;transition-property:border;position:absolute;inset:0}.lb-comment-attachments,.lb-composer-attachments{gap:calc(.75*var(--lb-spacing));grid-template-columns:repeat(auto-fill,minmax(min(100%,200px),1fr));display:grid}.lb-attachment,.lb-attachment-delete{all:unset;box-sizing:inherit;cursor:pointer;-webkit-user-select:none;user-select:none;transition-timing-function:var(--lb-transition-easing);transition-duration:var(--lb-transition-duration);-webkit-tap-highlight-color:transparent;outline:none;transition-property:background,color,opacity;position:relative}.lb-attachment:after,.lb-attachment-delete:after{content:"";border-radius:inherit;pointer-events:none;transition-property:box-shadow;position:absolute;inset:0}.lb-attachment:where(:focus-visible),.lb-attachment-delete:where(:focus-visible){z-index:1}.lb-attachment:where(:focus-visible):after,.lb-attachment-delete:where(:focus-visible):after{box-shadow:var(--lb-dynamic-background)0 0 0 2px,var(--lb-accent)0 0 0 4px}.lb-attachment{border-radius:var(--lb-radius);background:var(--lb-dynamic-background);box-shadow:inset 0 0 0 1px var(--lb-foreground-subtle);inline-size:100%;min-inline-size:0;position:relative}.lb-attachment:where([tabindex="-1"]){cursor:default}.lb-attachment:where(:not([tabindex="-1"])):where(:hover,:focus-visible){background:var(--lb-foreground-subtle)}.lb-attachment-delete{z-index:2;background:var(--lb-foreground-subtle);color:var(--lb-foreground-secondary);box-shadow:0 0 0 2px var(--lb-dynamic-background);opacity:0;border-radius:50%;justify-content:center;align-items:center;block-size:1.1rem;inline-size:1.1rem;display:flex;position:absolute;inset-block-start:-.35rem;inset-inline-end:-.35rem}.lb-attachment-delete:before{content:"";z-index:-1;border-radius:inherit;position:absolute;inset:-4px}.lb-attachment-delete:where(:hover,:focus-visible){background:var(--lb-foreground-secondary);color:var(--lb-dynamic-background)}:where(.lb-attachment:focus-within,.lb-attachment:hover) .lb-attachment-delete{opacity:1}.lb-attachment-delete :where(.lb-icon){inline-size:.75rem}.lb-attachment-name{display:flex}.lb-attachment-name-base,.lb-attachment-description{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lb-attachment-preview{position:relative}.lb-attachment-preview-image{border-radius:inherit;transition-property:opacity}.lb-attachment-preview-image,.lb-attachment-preview-image:after,.lb-attachment-preview-image img{block-size:100%;inline-size:100%;position:absolute;inset:0}.lb-attachment-preview-image img{object-fit:cover}.lb-attachment-preview-image:after{content:"";border-radius:inherit;box-shadow:var(--lb-highlight-shadow);pointer-events:none}.lb-attachment-preview-image:where([data-hidden]){opacity:0}.lb-attachment-icon{color:var(--lb-foreground);flex:none;overflow:visible}.lb-attachment-icon-glyph{fill:var(--lb-foreground-moderate)}.lb-attachment-icon-background{fill:var(--lb-background)}.lb-attachment-icon-fold{fill-opacity:calc(.75*var(--lb-foreground-contrast))}.lb-attachment-icon-shadow{filter:blur(6px);fill-opacity:var(--lb-foreground-contrast)}.lb-file-attachment{gap:calc(.5*var(--lb-spacing));padding:calc(.5*var(--lb-spacing));padding-inline-end:calc(.65*var(--lb-spacing));display:flex}.lb-file-attachment :where(.lb-attachment-preview){aspect-ratio:1;border-radius:calc(.5*var(--lb-radius));background:color-mix(in srgb,transparent,var(--lb-foreground)var(--lb-foreground-contrast));color:var(--lb-foreground-tertiary);flex:none;justify-content:center;align-items:center;inline-size:2.5rem;transition-property:background,color;display:flex;overflow:hidden}.lb-file-attachment:where([data-error]) :where(.lb-attachment-preview){background:var(--lb-destructive);color:var(--lb-destructive-foreground)}.lb-file-attachment :where(.lb-attachment-details){gap:calc(.25*var(--lb-spacing));flex-direction:column;justify-content:center;min-inline-size:0;font-size:.875em;display:flex}.lb-file-attachment :where(.lb-attachment-name),.lb-file-attachment :where(.lb-attachment-description){transition-property:color}.lb-file-attachment :where(.lb-attachment-name){color:var(--lb-foreground-secondary);font-weight:500}.lb-file-attachment :where(.lb-attachment-description){color:var(--lb-foreground-tertiary)}.lb-file-attachment :where(:not([tabindex="-1"])):where(:hover,:focus-visible) :where(.lb-attachment-name){color:var(--lb-foreground)}.lb-file-attachment :where(:not([tabindex="-1"])):where(:hover,:focus-visible) :where(.lb-attachment-description){color:var(--lb-foreground-secondary)}.lb-inbox-notification{--lb-inbox-notification-aside-size:36px;gap:calc(.75*var(--lb-spacing));padding:var(--lb-spacing);background:var(--lb-dynamic-background);color:var(--lb-foreground);-webkit-text-decoration:inherit;text-decoration:inherit;font-weight:400;transition-property:background;display:flex;position:relative;overflow:hidden}.lb-inbox-notification:where([data-missing]){--lb-dynamic-background:var(--lb-background-accent-faint);--lb-accent:var(--lb-destructive)!important;--lb-accent-foreground:var(--lb-destructive-foreground)!important;--lb-accent-contrast:var(--lb-destructive-contrast)!important}.lb-inbox-notification:where([data-unread]){--lb-dynamic-background:var(--lb-background-accent-faint)}.lb-inbox-notification:where([href]){cursor:pointer}.lb-inbox-notification:where([href]):where(:hover,:focus-visible,:focus-within){--lb-dynamic-background:var(--lb-background-foreground-faint)}.lb-inbox-notification:where([href]):where([data-unread]):where(:hover,:focus-visible,:focus-within){--lb-dynamic-background:var(--lb-background-accent-subtle)}.lb-inbox-notification-aside{inline-size:var(--lb-inbox-notification-aside-size);flex:none}.lb-inbox-notification-icon{aspect-ratio:1;background:var(--lb-foreground-subtle);border-radius:50%;justify-content:center;place-items:center;display:flex}.lb-inbox-notification:where([data-missing]) :where(.lb-inbox-notification-icon){background:var(--lb-accent-subtle);color:var(--lb-accent)}.lb-inbox-notification-content{flex:1}.lb-inbox-notification-content,.lb-inbox-notification-body{min-inline-size:0;max-inline-size:100%}.lb-inbox-notification-header{gap:calc(.75*var(--lb-spacing));align-items:center;margin-block-start:calc(.25*var(--lb-spacing));margin-block-end:calc(.5*var(--lb-spacing));display:flex}.lb-inbox-notification-title{min-block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size))}.lb-inbox-notification-title :where(strong,.lb-list,.lb-name){font-weight:500}.lb-inbox-notification-details{block-size:calc(2*.25*var(--lb-spacing) + var(--lb-icon-size));flex:none;align-self:start;min-inline-size:0;margin-inline-start:auto}.lb-inbox-notification-details-labels{align-items:baseline;min-inline-size:0;display:flex}.lb-inbox-notification-details-labels:before{content:""}.lb-inbox-notification-actions{gap:calc(.125*var(--lb-spacing));grid-area:actions;align-self:start;display:flex}.lb-inbox-notification-comments{gap:var(--lb-spacing);flex-direction:column;display:flex}.lb-inbox-notification-comment{background:0 0;padding:0}.lb-inbox-notification-comment :where(.lb-comment-header){color:var(--lb-foreground-tertiary);block-size:auto;font-size:.875rem}.lb-inbox-notification-comment :where(.lb-comment-reaction),.lb-inbox-notification-comment :where(.lb-comment-attachment){pointer-events:none}.lb-inbox-notification-date{color:var(--lb-foreground-tertiary);font-size:.875em}.lb-inbox-notification-unread-indicator{background:var(--lb-accent);border-radius:50%;align-self:center;block-size:10px;inline-size:10px;margin-inline-start:calc(.5*var(--lb-spacing))}.lb-inbox-notification-list{margin:0;padding:0;list-style:none}.lb-inbox-notification-list-item:where(:not(:last-of-type)){border-block-end:1px solid var(--lb-foreground-subtle)}.lb-root :where(code){border-radius:calc(.75*var(--lb-radius));background:var(--lb-foreground-subtle);-webkit-box-decoration-break:clone;box-decoration-break:clone;padding:.2em .4em;font-size:85%;line-height:1}.lb-root :where(span:has(code)+span code){border-start-start-radius:0;border-end-start-radius:0;padding-inline-start:0}.lb-root :where(span:has(code):has(+span code) code){border-start-end-radius:0;border-end-end-radius:0;padding-inline-end:0}:where(.lb-root code){font-family:ui-monospace,Menlo,Monaco,Roboto Mono,Cascadia Code,Source Code Pro,Consolas,DejaVu Sans Mono,monospace}.lb-elevation{border-radius:var(--lb-radius);background:var(--lb-dynamic-background);box-shadow:var(--lb-elevation-shadow);position:relative;overflow:hidden}.lb-elevation:after{content:"";z-index:1;border-radius:inherit;box-shadow:var(--lb-inset-shadow);pointer-events:none;position:absolute;inset:0}.lb-dropdown,.lb-composer-suggestions{padding:4px}.lb-dropdown-item,.lb-composer-suggestions-list-item{padding:calc(.25*var(--lb-spacing))calc(.5*var(--lb-spacing));align-items:center;font-size:.875rem;display:flex}.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji{border-radius:calc(var(--lb-radius) - .75*4px);color:var(--lb-foreground-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;transition-property:background,color,opacity}:is(.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji):where([data-highlighted],[data-selected]){background:var(--lb-foreground-subtle);transition-duration:calc(var(--lb-transition-duration)/2)}:is(.lb-dropdown-item,.lb-composer-suggestions-list-item,.lb-emoji-picker-emoji):where(:disabled,[data-disabled]){opacity:.5;cursor:not-allowed}.lb-dropdown,.lb-composer-suggestions,.lb-tooltip,.lb-emoji-picker{animation-duration:var(--lb-transition-duration);animation-timing-function:var(--lb-transition-easing);will-change:transform,opacity}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip:where([data-state=delayed-open]),.lb-composer-suggestions):where([data-side=top]){animation-name:lb-animation-slide-up}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip:where([data-state=delayed-open]),.lb-composer-suggestions):where([data-side=bottom]){animation-name:lb-animation-slide-down}:is(.lb-dropdown,.lb-emoji-picker,.lb-tooltip,.lb-composer-suggestions):where([data-state=closed]){animation-name:lb-animation-disappear}@keyframes lb-animation-slide-down{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes lb-animation-slide-up{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes lb-animation-appear{0%{opacity:0}to{opacity:1}}@keyframes lb-animation-disappear{0%{opacity:1}to{opacity:0}}@keyframes lb-animation-shimmer{0%,to{-webkit-mask-image:linear-gradient(90deg,#00000080,#000,#000,#00000080);mask-image:linear-gradient(90deg,#00000080,#000,#000,#00000080);-webkit-mask-size:400% 100%;mask-size:400% 100%}0%{-webkit-mask-position:200% 0;mask-position:200% 0}to{-webkit-mask-position:-200% 0;mask-position:-200% 0}}@keyframes lb-animation-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (hover:hover){.lb-comment:where(.lb-comment\:show-actions-hover) :where(.lb-comment-actions){opacity:0;transition-property:opacity;position:absolute;inset-inline-end:0}.lb-comment:where(.lb-comment\:show-actions-hover):where(:is(:hover,:focus-within,.lb-comment\:action-open)) :where(.lb-comment-actions){opacity:1;position:relative}.lb-thread:where(.lb-thread\:show-actions-hover :is(:hover,:focus-within)) :where(.lb-thread-actions){opacity:1}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-header){grid-template:"title secondary"/1fr max-content;display:grid}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-details){opacity:1;transition-property:opacity}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-actions){opacity:0;transition-property:opacity}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover):where(:is(:hover,:focus-within,.lb-inbox-notification\:action-open)) :where(.lb-inbox-notification-details){opacity:0}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover):where(:is(:hover,:focus-within,.lb-inbox-notification\:action-open)) :where(.lb-inbox-notification-actions){opacity:1}.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-details),.lb-inbox-notification:where(.lb-inbox-notification\:show-actions-hover) :where(.lb-inbox-notification-actions){grid-area:secondary;justify-self:end}}@media (prefers-reduced-motion){.lb-dropdown:where(:not([data-state=closed])),.lb-emoji-picker:where(:not([data-state=closed])),.lb-tooltip:where([data-state=delayed-open]:not([data-state=closed])),.lb-composer-suggestions:where(:not([data-state=closed])){animation-name:lb-animation-appear}}
|
package/styles.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["src/styles/src/styles/index.css","src/styles/src/styles/utils.css"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["@import \"./utils\";\n@import \"./constants\";\n\n.lb-root {\n /** \n * Basic\n */\n --lb-radius: 0.5em;\n --lb-spacing: 1em;\n --lb-accent: #17f;\n --lb-accent-foreground: #fff;\n --lb-destructive: #f45;\n --lb-destructive-foreground: #fff;\n --lb-background: #fff;\n --lb-foreground: #111;\n\n /** \n * Advanced\n */\n --lb-icon-size: 20px;\n --lb-icon-weight: 1.5px;\n --lb-avatar-radius: 50%;\n --lb-button-radius: calc(0.75 * var(--lb-radius));\n --lb-transition-duration: 0.1s;\n --lb-transition-easing: cubic-bezier(0.4, 0, 0.2, 1);\n --lb-highlight-shadow: inset 0 0 0 1px rgb(0 0 0 / 10%);\n --lb-elevation-shadow: $lb-elevation-shadow;\n --lb-tooltip-shadow: $lb-tooltip-shadow;\n --lb-accent-contrast: 8%;\n --lb-destructive-contrast: 8%;\n --lb-foreground-contrast: 8%;\n\n /** \n * Colors\n */\n --lb-background-foreground-faint: color-mix-scale(\n var(--lb-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 50\n );\n --lb-background-accent-faint: color-mix-scale(\n var(--lb-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 50\n );\n --lb-background-accent-subtle: color-mix-scale(\n var(--lb-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 100\n );\n --lb-accent-subtle: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 100\n );\n --lb-accent-moderate: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 400\n );\n --lb-accent-tertiary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 600\n );\n --lb-accent-secondary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 800\n );\n --lb-foreground-subtle: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 100\n );\n --lb-foreground-moderate: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 400\n );\n --lb-foreground-tertiary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 600\n );\n --lb-foreground-secondary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 800\n );\n --lb-selection: color-mix(in srgb, var(--lb-accent) 40%, transparent);\n\n overflow-wrap: break-word;\n accent-color: var(--lb-accent);\n text-size-adjust: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n &,\n *,\n ::before,\n ::after {\n box-sizing: border-box;\n transition: none var(--lb-transition-duration) var(--lb-transition-easing);\n }\n\n /* Define some variables only on first .lb-root instances */\n &:where(:not(& &)) {\n --lb-dynamic-background: var(--lb-background);\n }\n}\n\n/*************************************\n * Icon *\n *************************************/\n\n.lb-icon {\n --lb-icon-background: var(--lb-dynamic-background);\n\n inline-size: var(--lb-icon-size);\n block-size: var(--lb-icon-size);\n\n * {\n stroke-width: var(--lb-icon-weight);\n vector-effect: non-scaling-stroke;\n }\n}\n\n.lb-icon-spinner {\n transform-origin: center;\n animation: lb-animation-spin 0.75s linear infinite;\n}\n\n/*************************************\n * Button *\n *************************************/\n\n.lb-button {\n --lb-button-background: var(--lb-dynamic-background);\n\n @include button;\n\n display: flex;\n justify-content: center;\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing));\n border-radius: var(--lb-button-radius);\n background: var(--lb-button-background);\n color: var(--lb-foreground-moderate);\n\n &:where(.lb-button\\:non-disableable:disabled) {\n cursor: default;\n }\n\n &:where(:not(.lb-button\\:non-disableable):disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n --lb-button-background: var(--lb-foreground-subtle);\n\n color: var(--lb-foreground-tertiary);\n }\n\n &:where(\n [data-variant=\"default\"]:not(\n :is(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n )\n )\n ) {\n background: transparent;\n }\n\n &:where([data-variant=\"primary\"]) {\n --lb-button-background: var(--lb-accent);\n\n color: var(--lb-accent-foreground);\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n --lb-button-background: var(--lb-accent-secondary);\n\n color: var(--lb-accent-foreground);\n }\n }\n\n &:where([data-variant=\"outline\"]) {\n box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle);\n transition-property: background, color, opacity, box-shadow;\n }\n}\n\n.lb-button-icon {\n --lb-icon-background: var(--lb-button-background);\n}\n\n/*************************************\n * Dropdown *\n *************************************/\n\n.lb-dropdown-item-icon {\n margin-inline-start: calc(-0.125 * var(--lb-spacing));\n margin-inline-end: calc(0.375 * var(--lb-spacing));\n color: var(--lb-foreground-moderate);\n transition-property: color;\n}\n\n.lb-dropdown-item:where(:is([data-highlighted], [data-selected])) {\n :where(.lb-dropdown-item-icon) {\n color: var(--lb-foreground-tertiary);\n }\n}\n\n/*************************************\n * Composer suggestions *\n *************************************/\n\n.lb-composer-suggestions-list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.lb-composer-suggestions-list-item {\n scroll-margin-block: $lb-elevation-list-padding;\n}\n\n/*************************************\n * Composer mention suggestions *\n *************************************/\n\n.lb-composer-mention-suggestions {\n --lb-composer-mention-suggestion-avatar-size: 1.25rem;\n}\n\n.lb-composer-mention-suggestion {\n padding: calc(0.375 * var(--lb-spacing)) calc(0.625 * var(--lb-spacing));\n}\n\n.lb-composer-mention-suggestion-avatar {\n inline-size: var(--lb-composer-mention-suggestion-avatar-size);\n margin-inline-start: calc(-0.125 * var(--lb-spacing));\n margin-inline-end: calc(0.5 * var(--lb-spacing));\n margin-block: calc(0.125 * var(--lb-spacing));\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-moderate);\n}\n\n/*************************************\n * List *\n *************************************/\n\n.lb-list {\n display: contents;\n}\n\n/*************************************\n * Emoji *\n *************************************/\n\n@include safari-only {\n .lb-emoji {\n transform: scale(0.825);\n will-change: transform;\n }\n}\n\n/*************************************\n * Emoji picker *\n *************************************/\n\n.lb-emoji-picker {\n --lb-emoji-picker-padding: $lb-emoji-picker-padding;\n --lb-emoji-picker-offset-padding: calc(\n $lb-emoji-picker-padding + 0.375 * var(--lb-spacing)\n );\n\n display: flex;\n flex-direction: column;\n block-size: 360px;\n color: var(--lb-foreground);\n}\n\n.lb-emoji-picker-header {\n flex: none;\n border-block-end: 1px solid var(--lb-foreground-subtle);\n}\n\n.lb-emoji-picker-search-container {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.lb-emoji-picker-search {\n all: unset;\n box-sizing: inherit;\n inline-size: 100%;\n padding: var(--lb-emoji-picker-offset-padding);\n padding-inline-start: calc(\n var(--lb-icon-size) + var(--lb-emoji-picker-offset-padding) + 0.375 *\n var(--lb-spacing)\n );\n background: transparent;\n outline: none;\n appearance: textfield;\n\n &::placeholder {\n color: var(--lb-foreground-moderate);\n }\n\n &::-webkit-search-cancel-button {\n display: none;\n }\n}\n\n.lb-emoji-picker-search-icon {\n position: absolute;\n inset-inline-start: var(--lb-emoji-picker-offset-padding);\n color: var(--lb-foreground-moderate);\n pointer-events: none;\n}\n\n.lb-emoji-picker-content {\n position: relative;\n flex: 1;\n}\n\n.lb-emoji-picker-loading,\n.lb-emoji-picker-empty,\n.lb-emoji-picker-error {\n position: absolute;\n inset: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.lb-emoji-picker-loading {\n color: var(--lb-foreground-moderate);\n}\n\n.lb-emoji-picker-empty,\n.lb-emoji-picker-error {\n padding: var(--lb-spacing);\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n text-align: center;\n text-wrap: balance;\n}\n\n.lb-emoji-picker-category-header {\n padding: var(--lb-emoji-picker-padding) var(--lb-emoji-picker-offset-padding);\n background: var(--lb-dynamic-background);\n}\n\n.lb-emoji-picker-category-header-title {\n color: var(--lb-foreground-tertiary);\n font-weight: 600;\n font-size: 0.675em;\n text-transform: uppercase;\n}\n\n.lb-emoji-picker-grid {\n position: absolute;\n inset: 0;\n animation: lb-animation-appear var(--lb-transition-duration)\n var(--lb-transition-easing) both;\n}\n\n.lb-emoji-picker-row {\n display: flex;\n padding-inline: var(--lb-emoji-picker-padding);\n scroll-margin-block-end: var(--lb-emoji-picker-padding);\n\n &:where([data-last]) {\n padding-block-end: var(--lb-emoji-picker-padding);\n }\n}\n\n.lb-emoji-picker-emoji {\n all: unset;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n box-sizing: inherit;\n aspect-ratio: 1;\n padding: calc(0.375 * var(--lb-spacing));\n border-radius: calc(var(--lb-radius) - 0.75 * $lb-emoji-picker-padding);\n text-align: center;\n}\n\n/*************************************\n * Tooltip *\n *************************************/\n\n.lb-tooltip {\n --lb-background: #222;\n --lb-foreground: #fff;\n --lb-foreground-contrast: 10%;\n\n position: relative;\n display: flex;\n align-items: center;\n max-inline-size: 300px;\n min-block-size: calc(\n $lb-tooltip-shortcut-height + 2 * $lb-tooltip-additional-padding\n );\n padding-inline: $lb-tooltip-horizontal-padding;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n box-shadow: var(--lb-tooltip-shadow);\n font-size: 0.75rem;\n line-height: 1;\n overflow-wrap: anywhere;\n pointer-events: none;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n z-index: 1;\n border-radius: inherit;\n box-shadow: var(--lb-inset-shadow);\n pointer-events: none;\n }\n}\n\n.lb-tooltip\\:multiline {\n justify-content: center;\n padding-block: calc(\n $lb-tooltip-vertical-padding * (1 / $lb-tooltip-line-height)\n );\n line-height: $lb-tooltip-line-height;\n text-align: center;\n}\n\n.lb-tooltip-shortcut {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n justify-content: center;\n align-items: center;\n block-size: $lb-tooltip-shortcut-height;\n margin-inline-start: $lb-tooltip-horizontal-padding;\n margin-inline-end: calc(\n -1 * $lb-tooltip-horizontal-padding + $lb-tooltip-additional-padding\n );\n padding-inline: calc(0.25 * var(--lb-spacing));\n border-radius: calc(\n var(--lb-radius) - 0.625 * $lb-tooltip-additional-padding\n );\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-tertiary);\n font-family: inherit;\n line-height: 1;\n text-transform: uppercase;\n\n :where(abbr) {\n all: unset;\n }\n}\n\n/*************************************\n * Avatar *\n *************************************/\n\n.lb-avatar {\n position: relative;\n container-type: inline-size;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n aspect-ratio: 1;\n border-radius: var(--lb-avatar-radius);\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-moderate);\n\n &:where([data-loading]) {\n background: var(--lb-foreground);\n opacity: $lb-loading-opacity;\n }\n}\n\n.lb-avatar-image {\n position: absolute;\n inset: 0;\n object-fit: cover;\n inline-size: 100%;\n block-size: 100%;\n}\n\n.lb-avatar-fallback {\n font-weight: 500;\n font-size: 35cqi;\n white-space: nowrap;\n\n /**\n * Progressive enhancement: Only show the fallback when container queries are supported\n */\n @supports not (container-type: inline-size) {\n display: none;\n }\n}\n\n/*************************************\n * Name *\n *************************************/\n\n.lb-name:where([data-loading]) {\n &::before {\n content: \"\\FEFF\";\n display: inline-block;\n vertical-align: middle;\n inline-size: 8ch;\n block-size: 1.75ex;\n border-radius: calc(0.5 * var(--lb-radius));\n background: currentcolor;\n opacity: $lb-loading-opacity;\n user-select: none;\n }\n}\n\n/*************************************\n * Loading *\n *************************************/\n\n:is(.lb-avatar, .lb-name):where([data-loading]) {\n animation: lb-animation-shimmer 8s linear infinite;\n}\n\n/*************************************\n * Body *\n *************************************/\n\n:is(.lb-comment-body, .lb-composer-editor) {\n color: var(--lb-foreground-secondary);\n\n :where(p) {\n margin-block-start: 0.25em;\n margin-block-end: 0.25em;\n\n &:where(:first-of-type) {\n margin-block-start: 0;\n }\n\n &:where(:last-of-type) {\n margin-block-end: 0;\n }\n }\n\n :where(strong) {\n font-weight: 600;\n }\n}\n\n.lb-comment-mention,\n.lb-composer-mention {\n color: var(--lb-accent);\n box-decoration-break: clone;\n font-weight: 500;\n}\n\n:is(.lb-comment-link, .lb-composer-link) {\n color: var(--lb-foreground);\n outline: none;\n font-weight: 500;\n transition-property: color, text-decoration-color;\n text-decoration-line: underline;\n text-decoration-color: var(--lb-foreground-moderate);\n text-underline-offset: 2px;\n\n &:where([href]):where(:hover, :focus-visible) {\n color: var(--lb-accent);\n text-decoration-color: var(--lb-accent-moderate);\n }\n}\n\n.lb-comment-mention:where([data-self]),\n.lb-composer-mention {\n padding: 0.1em 0.3em;\n border-radius: calc(0.675 * var(--lb-radius));\n background: var(--lb-accent-subtle);\n}\n\n/*************************************\n * Composer *\n *************************************/\n\n.lb-composer {\n position: relative;\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n transition-property: background;\n}\n\n.lb-composer-form {\n margin: 0;\n}\n\n.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) {\n :where(.lb-button[data-variant=\"primary\"]) {\n --lb-button-background: var(--lb-foreground-subtle);\n\n color: var(--lb-foreground-tertiary);\n\n &:where(:enabled:hover, :enabled:focus-visible) {\n --lb-button-background: var(--lb-accent);\n\n color: var(--lb-accent-foreground);\n }\n }\n}\n\n.lb-composer-editor {\n padding: var(--lb-spacing);\n outline: none;\n\n :where([data-placeholder]) {\n color: var(--lb-foreground-moderate);\n }\n}\n\n.lb-composer-mention {\n @include invisible-selection;\n\n &:where([data-selected]) {\n background: var(--lb-accent);\n color: var(--lb-accent-foreground);\n }\n}\n\n.lb-composer-footer {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n block-size: calc($lb-button-size + var(--lb-spacing));\n margin-block-start: calc(-0.125 * var(--lb-spacing));\n padding: 0 var(--lb-spacing) var(--lb-spacing);\n}\n\n.lb-composer-actions,\n.lb-composer-editor-actions {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n align-items: center;\n}\n\n.lb-composer-editor-actions {\n margin-inline-end: auto;\n}\n\n.lb-composer-attribution {\n color: var(--lb-foreground-moderate);\n outline: none;\n transition-property: color;\n\n &:where(:hover, :focus-visible) {\n color: var(--lb-foreground-tertiary);\n }\n\n :where(svg) {\n block-size: calc(0.75 * $lb-button-size);\n }\n}\n\n.lb-composer-editor:where(:has(+ .lb-composer-attachments)) {\n padding-block-end: calc(0.25 * var(--lb-spacing));\n}\n\n.lb-composer-attachments {\n padding-inline: var(--lb-spacing);\n padding-block-start: calc(0.75 * var(--lb-spacing));\n padding-block-end: var(--lb-spacing);\n}\n\n.lb-composer-editor-container:where([data-drop]) * {\n pointer-events: none;\n}\n\n.lb-composer-attachments-drop-area {\n position: absolute;\n inset: 0;\n display: flex;\n place-content: center;\n place-items: center;\n color: var(--lb-accent);\n\n &::before,\n &::after {\n content: \"\";\n position: absolute;\n inset: calc(0.5 * var(--lb-spacing));\n z-index: 0;\n border-radius: calc(0.75 * var(--lb-radius));\n }\n\n &::before {\n background: currentcolor;\n opacity: calc(1 * var(--lb-accent-contrast));\n }\n\n &::after {\n border: 2px dashed currentcolor;\n opacity: calc(2 * var(--lb-accent-contrast));\n }\n}\n\n.lb-composer-attachments-drop-area-label {\n position: relative;\n display: flex;\n gap: calc(0.25 * var(--lb-spacing));\n place-items: center;\n padding: calc(0.375 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing));\n border-radius: calc(0.75 * var(--lb-radius));\n background: var(--lb-accent);\n color: var(--lb-accent-foreground);\n font-weight: 500;\n pointer-events: none;\n}\n\n/*************************************\n * Comment *\n *************************************/\n\n.lb-comment {\n --lb-comment-avatar-size: $lb-button-size;\n\n position: relative;\n padding: var(--lb-spacing);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n font-weight: 400;\n scroll-margin: var(--lb-spacing);\n\n @media (hover: hover) {\n &:where(.lb-comment\\:show-actions-hover) {\n :where(.lb-comment-actions) {\n position: absolute;\n inset-inline-end: 0;\n opacity: 0;\n transition-property: opacity;\n }\n\n &:where(:is(:hover, :focus-within, .lb-comment\\:action-open)) {\n :where(.lb-comment-actions) {\n position: relative;\n opacity: 1;\n }\n }\n }\n }\n\n &:where(:target, [data-target]) {\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([data-editing]) {\n --lb-dynamic-background: var(--lb-background-foreground-faint);\n }\n}\n\n.lb-comment-header {\n position: relative;\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n block-size: var(--lb-comment-avatar-size);\n margin-block-end: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-details {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n min-inline-size: 0;\n}\n\n.lb-comment-avatar {\n flex: none;\n inline-size: var(--lb-comment-avatar-size);\n}\n\n.lb-comment-details-labels {\n display: flex;\n gap: calc(0.5 * var(--lb-spacing));\n align-items: baseline;\n min-inline-size: 0;\n}\n\n.lb-comment-author {\n @include truncate;\n\n font-weight: 500;\n}\n\n.lb-comment-date {\n @include truncate;\n\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-comment-date-created,\n.lb-comment-date-edited {\n display: contents;\n}\n\n.lb-comment-actions {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n margin-inline-start: auto;\n}\n\n.lb-comment-composer {\n margin: calc(-1 * var(--lb-spacing));\n background: unset;\n}\n\n.lb-comment-body {\n /**\n * Prevent empty lines from collapsing\n */\n :where(p span:only-child:empty)::before {\n content: \"\\FEFF\";\n user-select: none;\n }\n}\n\n.lb-comment-attachments {\n margin-block-start: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-reactions {\n display: flex;\n flex-wrap: wrap;\n gap: calc(0.375 * var(--lb-spacing));\n margin-block-start: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-reaction {\n gap: calc(0.375 * var(--lb-spacing));\n block-size: $lb-button-size;\n padding-inline: calc(0.575 * var(--lb-spacing));\n border-radius: $lb-radius-full;\n\n &:where([data-self]) {\n background: var(--lb-accent-subtle);\n color: var(--lb-accent-secondary);\n box-shadow: inset 0 0 0 1px var(--lb-accent-moderate);\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n color: var(--lb-accent);\n }\n }\n}\n\n.lb-comment-reaction-count {\n font-weight: 500;\n font-size: 0.75em;\n font-variant-numeric: tabular-nums;\n}\n\n.lb-comment-reaction-tooltip {\n max-inline-size: 200px;\n}\n\n.lb-comment-deleted {\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-comment\\:indent-content {\n min-block-size: calc(var(--lb-comment-avatar-size) + 2 * var(--lb-spacing));\n\n :where(.lb-comment-header) {\n block-size: $lb-button-size;\n margin-block-end: calc(0.25 * var(--lb-spacing));\n }\n\n :where(.lb-comment-avatar) {\n position: absolute;\n inset-inline-start: 0;\n inset-block-start: 0;\n }\n\n :where(.lb-comment-details-labels) {\n margin-inline-start: calc(\n var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing)\n );\n }\n\n :where(.lb-comment-content) {\n padding-inline-start: calc(\n var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing)\n );\n }\n}\n\n/*************************************\n * Thread *\n *************************************/\n\n.lb-thread {\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n transition-property: background;\n\n @media (hover: hover) {\n &:where(.lb-thread\\:show-actions-hover :is(:hover, :focus-within)) {\n :where(.lb-thread-actions) {\n opacity: 1;\n }\n }\n }\n}\n\n.lb-thread-comments {\n position: relative;\n z-index: 0;\n display: flex;\n flex-direction: column;\n}\n\n.lb-thread-comment {\n z-index: 0;\n padding-block: calc(0.6 * var(--lb-spacing));\n transition-property: background;\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(var(--lb-comment-avatar-size) + var(--lb-spacing));\n }\n\n &:where(:first-of-type, [data-editing]) {\n padding-block-start: var(--lb-spacing);\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(\n var(--lb-comment-avatar-size) + 1.5 * var(--lb-spacing)\n );\n }\n }\n\n &:where(:last-of-type, [data-editing]) {\n padding-block-end: var(--lb-spacing);\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(\n var(--lb-comment-avatar-size) + 1.75 * var(--lb-spacing)\n );\n }\n }\n}\n\n.lb-thread-new-indicator {\n position: relative;\n z-index: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n block-size: 0;\n\n &::before,\n &::after {\n content: \"\";\n z-index: 0;\n flex: 1;\n block-size: 0;\n border-block-start: 1px solid var(--lb-foreground-subtle);\n transition-property: border;\n }\n}\n\n.lb-thread-new-indicator-label {\n z-index: 1;\n display: flex;\n flex: none;\n gap: calc(0.325 * var(--lb-spacing));\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing)) var(--lb-spacing);\n color: var(--lb-accent);\n font-weight: 600;\n font-size: 0.675em;\n text-transform: uppercase;\n}\n\n.lb-thread-new-indicator-label-icon {\n inline-size: calc(0.6 * var(--lb-icon-size));\n block-size: calc(0.6 * var(--lb-icon-size));\n}\n\n.lb-thread-composer {\n position: relative;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n border-block-start: 1px solid var(--lb-foreground-subtle);\n pointer-events: none;\n transition-property: border;\n }\n}\n\n/*************************************\n * Attachments *\n *************************************/\n\n.lb-comment-attachments,\n.lb-composer-attachments {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));\n gap: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-attachment,\n.lb-attachment-delete {\n @include button;\n}\n\n.lb-attachment {\n position: relative;\n inline-size: 100%;\n min-inline-size: 0;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle);\n\n &:where([tabindex=\"-1\"]) {\n cursor: default;\n }\n\n &:where(:not([tabindex=\"-1\"])) {\n &:where(:hover, :focus-visible) {\n background: var(--lb-foreground-subtle);\n }\n }\n}\n\n.lb-attachment-delete {\n position: absolute;\n inset-inline-end: -0.35rem;\n inset-block-start: -0.35rem;\n z-index: 2;\n display: flex;\n justify-content: center;\n align-items: center;\n inline-size: 1.1rem;\n block-size: 1.1rem;\n border-radius: 50%;\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-secondary);\n box-shadow: 0 0 0 2px var(--lb-dynamic-background);\n opacity: 0;\n\n /* Invisibly increase the button's hit target size */\n &::before {\n content: \"\";\n position: absolute;\n inset: -4px;\n z-index: -1;\n border-radius: inherit;\n }\n\n &:where(:hover, :focus-visible) {\n background: var(--lb-foreground-secondary);\n color: var(--lb-dynamic-background);\n }\n\n :where(.lb-attachment:focus-within, .lb-attachment:hover) & {\n opacity: 1;\n }\n\n :where(.lb-icon) {\n inline-size: 0.75rem;\n }\n}\n\n.lb-attachment-name {\n display: flex;\n}\n\n.lb-attachment-name-base,\n.lb-attachment-description {\n @include truncate;\n}\n\n.lb-attachment-preview {\n position: relative;\n}\n\n.lb-attachment-preview-image {\n border-radius: inherit;\n transition-property: opacity;\n\n &,\n &::after,\n img {\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n }\n\n img {\n object-fit: cover;\n }\n\n &::after {\n content: \"\";\n border-radius: inherit;\n box-shadow: var(--lb-highlight-shadow);\n pointer-events: none;\n }\n\n &:where([data-hidden]) {\n opacity: 0;\n }\n}\n\n.lb-attachment-icon {\n flex: none;\n overflow: visible;\n color: var(--lb-foreground);\n}\n\n.lb-attachment-icon-glyph {\n fill: var(--lb-foreground-moderate);\n}\n\n.lb-attachment-icon-background {\n fill: var(--lb-background);\n}\n\n.lb-attachment-icon-fold {\n fill-opacity: calc(0.75 * var(--lb-foreground-contrast));\n}\n\n.lb-attachment-icon-shadow {\n filter: blur(6px);\n fill-opacity: var(--lb-foreground-contrast);\n}\n\n.lb-file-attachment {\n display: flex;\n gap: calc(0.5 * var(--lb-spacing));\n padding: calc(0.5 * var(--lb-spacing));\n padding-inline-end: calc(0.65 * var(--lb-spacing));\n\n :where(.lb-attachment-preview) {\n display: flex;\n flex: none;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n aspect-ratio: 1;\n inline-size: 2.5rem;\n border-radius: calc(0.5 * var(--lb-radius));\n background: color-mix(\n in srgb,\n transparent,\n var(--lb-foreground) var(--lb-foreground-contrast)\n );\n color: var(--lb-foreground-tertiary);\n transition-property: background, color;\n }\n\n &:where([data-error]) {\n :where(.lb-attachment-preview) {\n background: var(--lb-destructive);\n color: var(--lb-destructive-foreground);\n }\n }\n\n :where(.lb-attachment-details) {\n display: flex;\n flex-direction: column;\n gap: calc(0.25 * var(--lb-spacing));\n justify-content: center;\n min-inline-size: 0;\n font-size: 0.875em;\n }\n\n :where(.lb-attachment-name),\n :where(.lb-attachment-description) {\n transition-property: color;\n }\n\n :where(.lb-attachment-name) {\n color: var(--lb-foreground-secondary);\n font-weight: 500;\n }\n\n :where(.lb-attachment-description) {\n color: var(--lb-foreground-tertiary);\n }\n\n :where(:not([tabindex=\"-1\"])) {\n &:where(:hover, :focus-visible) {\n :where(.lb-attachment-name) {\n color: var(--lb-foreground);\n }\n\n :where(.lb-attachment-description) {\n color: var(--lb-foreground-secondary);\n }\n }\n }\n}\n\n/*************************************\n * Inbox Notification *\n *************************************/\n\n.lb-inbox-notification {\n --lb-inbox-notification-aside-size: 36px;\n\n position: relative;\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n overflow: hidden;\n padding: var(--lb-spacing);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n font-weight: 400;\n text-decoration: inherit;\n transition-property: background;\n\n /* Highlight missing notifications during development */\n &:where([data-missing]) {\n --lb-accent: var(--lb-destructive) !important;\n --lb-accent-foreground: var(--lb-destructive-foreground) !important;\n --lb-accent-contrast: var(--lb-destructive-contrast) !important;\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([data-unread]) {\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([href]) {\n cursor: pointer;\n\n &:where(:hover, :focus-visible, :focus-within) {\n --lb-dynamic-background: var(--lb-background-foreground-faint);\n }\n\n &:where([data-unread]) {\n &:where(:hover, :focus-visible, :focus-within) {\n --lb-dynamic-background: var(--lb-background-accent-subtle);\n }\n }\n }\n\n @media (hover: hover) {\n &:where(.lb-inbox-notification\\:show-actions-hover) {\n :where(.lb-inbox-notification-header) {\n display: grid;\n grid-template: \"title secondary\" / 1fr max-content;\n }\n\n :where(.lb-inbox-notification-details) {\n opacity: 1;\n transition-property: opacity;\n }\n\n :where(.lb-inbox-notification-actions) {\n opacity: 0;\n transition-property: opacity;\n }\n\n &:where(:is(:hover, :focus-within, .lb-inbox-notification\\:action-open)) {\n :where(.lb-inbox-notification-details) {\n opacity: 0;\n }\n\n :where(.lb-inbox-notification-actions) {\n opacity: 1;\n }\n }\n\n :where(.lb-inbox-notification-details),\n :where(.lb-inbox-notification-actions) {\n grid-area: secondary;\n justify-self: end;\n }\n }\n }\n}\n\n.lb-inbox-notification-aside {\n flex: none;\n inline-size: var(--lb-inbox-notification-aside-size);\n}\n\n.lb-inbox-notification-icon {\n display: flex;\n justify-content: center;\n place-items: center;\n aspect-ratio: 1;\n border-radius: 50%;\n background: var(--lb-foreground-subtle);\n\n .lb-inbox-notification:where([data-missing]) :where(&) {\n background: var(--lb-accent-subtle);\n color: var(--lb-accent);\n }\n}\n\n.lb-inbox-notification-content {\n flex: 1;\n}\n\n.lb-inbox-notification-content,\n.lb-inbox-notification-body {\n min-inline-size: 0;\n max-inline-size: 100%;\n}\n\n.lb-inbox-notification-header {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n margin-block-start: calc(0.25 * var(--lb-spacing));\n margin-block-end: calc(0.5 * var(--lb-spacing));\n}\n\n.lb-inbox-notification-title {\n min-block-size: $lb-button-size;\n\n :where(strong, .lb-list, .lb-name) {\n font-weight: 500;\n }\n}\n\n.lb-inbox-notification-details {\n flex: none;\n align-self: start;\n min-inline-size: 0;\n block-size: $lb-button-size;\n margin-inline-start: auto;\n}\n\n.lb-inbox-notification-details-labels {\n display: flex;\n align-items: baseline;\n min-inline-size: 0;\n\n &::before {\n content: \"\\FEFF\";\n }\n}\n\n.lb-inbox-notification-actions {\n display: flex;\n grid-area: actions;\n gap: calc(0.125 * var(--lb-spacing));\n align-self: start;\n}\n\n.lb-inbox-notification-comments {\n display: flex;\n flex-direction: column;\n gap: var(--lb-spacing);\n}\n\n.lb-inbox-notification-comment {\n padding: 0;\n background: transparent;\n\n :where(.lb-comment-header) {\n block-size: auto;\n color: var(--lb-foreground-tertiary);\n font-size: 0.875rem;\n }\n\n :where(.lb-comment-reaction),\n :where(.lb-comment-attachment) {\n pointer-events: none;\n }\n}\n\n.lb-inbox-notification-date {\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-inbox-notification-unread-indicator {\n align-self: center;\n inline-size: 10px;\n block-size: 10px;\n margin-inline-start: calc(0.5 * var(--lb-spacing));\n border-radius: 50%;\n background: var(--lb-accent);\n}\n\n/*************************************\n * Inbox Notification List *\n *************************************/\n\n.lb-inbox-notification-list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.lb-inbox-notification-list-item {\n &:where(:not(:last-of-type)) {\n border-block-end: 1px solid var(--lb-foreground-subtle);\n }\n}\n\n/*************************************\n * Inline code *\n *************************************/\n\n:is(.lb-root) {\n :where(code) {\n padding: 0.2em 0.4em;\n border-radius: calc(0.75 * var(--lb-radius));\n background: var(--lb-foreground-subtle);\n box-decoration-break: clone;\n font-size: 85%;\n line-height: 1;\n }\n\n /**\n * Merge adjacent inline code elements\n */\n :where(span:has(code) + span code) {\n padding-inline-start: 0;\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n :where(span:has(code):has(+ span code) code) {\n padding-inline-end: 0;\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n}\n\n/* 0,0,0 specificity to inherit any styles applied to `code` elements */\n:where(:is(.lb-root) code) {\n font-family: ui-monospace, Menlo, Monaco, \"Roboto Mono\", \"Cascadia Code\",\n \"Source Code Pro\", Consolas, \"DejaVu Sans Mono\", monospace;\n}\n\n/*************************************\n * Elevation *\n *************************************/\n\n.lb-elevation {\n position: relative;\n overflow: hidden;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n box-shadow: var(--lb-elevation-shadow);\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n z-index: 1;\n border-radius: inherit;\n box-shadow: var(--lb-inset-shadow);\n pointer-events: none;\n }\n}\n\n/*************************************\n * Elevation lists *\n *************************************/\n\n.lb-dropdown,\n.lb-composer-suggestions {\n padding: $lb-elevation-list-padding;\n}\n\n.lb-dropdown-item,\n.lb-composer-suggestions-list-item {\n display: flex;\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing));\n font-size: 0.875rem;\n}\n\n.lb-dropdown-item,\n.lb-composer-suggestions-list-item,\n.lb-emoji-picker-emoji {\n border-radius: calc(var(--lb-radius) - 0.75 * $lb-elevation-list-padding);\n color: var(--lb-foreground-secondary);\n outline: none;\n cursor: pointer;\n user-select: none;\n transition-property: background, color, opacity;\n}\n\n:is(\n .lb-dropdown-item,\n .lb-composer-suggestions-list-item,\n .lb-emoji-picker-emoji\n ) {\n &:where([data-highlighted], [data-selected]) {\n background: var(--lb-foreground-subtle);\n transition-duration: calc(var(--lb-transition-duration) / 2);\n }\n\n &:where(:disabled, [data-disabled]) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n}\n\n/*************************************\n * Floating animations *\n *************************************/\n\n.lb-dropdown,\n.lb-composer-suggestions,\n.lb-tooltip,\n.lb-emoji-picker {\n animation-duration: var(--lb-transition-duration);\n animation-timing-function: var(--lb-transition-easing);\n will-change: transform, opacity;\n}\n\n:is(\n .lb-dropdown,\n .lb-emoji-picker,\n .lb-tooltip:where([data-state=\"delayed-open\"]),\n .lb-composer-suggestions\n ) {\n &:where([data-side=\"top\"]) {\n animation-name: lb-animation-slide-up;\n }\n\n &:where([data-side=\"bottom\"]) {\n animation-name: lb-animation-slide-down;\n }\n}\n\n:is(.lb-dropdown, .lb-emoji-picker, .lb-tooltip, .lb-composer-suggestions) {\n &:where([data-state=\"closed\"]) {\n animation-name: lb-animation-disappear;\n }\n}\n\n@media (prefers-reduced-motion) {\n .lb-dropdown:where(:not([data-state=\"closed\"])),\n .lb-emoji-picker:where(:not([data-state=\"closed\"])),\n .lb-tooltip:where([data-state=\"delayed-open\"]:not([data-state=\"closed\"])),\n .lb-composer-suggestions:where(:not([data-state=\"closed\"])) {\n animation-name: lb-animation-appear;\n }\n}\n\n/*************************************\n * Animations *\n *************************************/\n\n@keyframes lb-animation-slide-down {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes lb-animation-slide-up {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes lb-animation-appear {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes lb-animation-disappear {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes lb-animation-shimmer {\n from,\n to {\n mask-image: linear-gradient(\n 90deg,\n rgb(0 0 0 / 50%),\n #000,\n #000,\n rgb(0 0 0 / 50%)\n );\n mask-size: 400% 100%;\n }\n\n from {\n mask-position: 200% 0;\n }\n\n to {\n mask-position: -200% 0;\n }\n}\n\n@keyframes lb-animation-spin {\n from {\n transform: rotate(0deg);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n","/* Because of `all: unset`, we have to re-define some these values. */\n@mixin button {\n all: unset;\n position: relative;\n box-sizing: inherit;\n outline: none;\n cursor: pointer;\n user-select: none;\n transition-timing-function: var(--lb-transition-easing);\n transition-duration: var(--lb-transition-duration);\n transition-property: background, color, opacity;\n -webkit-tap-highlight-color: transparent;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n transition-property: box-shadow;\n }\n\n &:where(:focus-visible) {\n z-index: 1;\n\n &::after {\n box-shadow:\n var(--lb-dynamic-background) 0 0 0 2px,\n var(--lb-accent) 0 0 0 4px;\n }\n }\n}\n\n@mixin truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@mixin invisible-selection {\n &::selection,\n *::selection {\n background: transparent;\n }\n}\n\n@mixin invisible-scrollbar {\n & {\n -ms-overflow-style: none;\n scrollbar-width: none;\n }\n\n &::-webkit-scrollbar {\n display: none;\n }\n}\n\n@mixin firefox-only {\n @supports (-moz-appearance: none) {\n @content;\n }\n}\n\n@mixin not-firefox {\n @supports not (-moz-appearance: none) {\n @content;\n }\n}\n\n@mixin safari-only {\n @supports (background: -webkit-named-image(i)) {\n @content;\n }\n}\n\n@mixin not-safari {\n @supports not (background: -webkit-named-image(i)) {\n @content;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["src/styles/src/styles/index.css","src/styles/src/styles/utils.css"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["@import \"./utils\";\n@import \"./constants\";\n\n.lb-root {\n /** \n * Basic\n */\n --lb-radius: 0.5em;\n --lb-spacing: 1em;\n --lb-accent: #17f;\n --lb-accent-foreground: #fff;\n --lb-destructive: #f45;\n --lb-destructive-foreground: #fff;\n --lb-background: #fff;\n --lb-foreground: #111;\n\n /** \n * Advanced\n */\n --lb-icon-size: 20px;\n --lb-icon-weight: 1.5px;\n --lb-avatar-radius: 50%;\n --lb-button-radius: calc(0.75 * var(--lb-radius));\n --lb-transition-duration: 0.1s;\n --lb-transition-easing: cubic-bezier(0.4, 0, 0.2, 1);\n --lb-highlight-shadow: inset 0 0 0 1px rgb(0 0 0 / 10%);\n --lb-elevation-shadow: $lb-elevation-shadow;\n --lb-tooltip-shadow: $lb-tooltip-shadow;\n --lb-accent-contrast: 8%;\n --lb-destructive-contrast: 8%;\n --lb-foreground-contrast: 8%;\n\n /** \n * Colors\n */\n --lb-background-foreground-faint: color-mix-scale(\n var(--lb-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 50\n );\n --lb-background-accent-faint: color-mix-scale(\n var(--lb-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 50\n );\n --lb-background-accent-subtle: color-mix-scale(\n var(--lb-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 100\n );\n --lb-accent-subtle: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 100\n );\n --lb-accent-moderate: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 400\n );\n --lb-accent-tertiary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 600\n );\n --lb-accent-secondary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-accent),\n var(--lb-accent-contrast),\n 800\n );\n --lb-foreground-subtle: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 100\n );\n --lb-foreground-moderate: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 400\n );\n --lb-foreground-tertiary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 600\n );\n --lb-foreground-secondary: color-mix-scale(\n var(--lb-dynamic-background),\n var(--lb-foreground),\n var(--lb-foreground-contrast),\n 800\n );\n --lb-selection: color-mix(in srgb, var(--lb-accent) 40%, transparent);\n\n overflow-wrap: break-word;\n accent-color: var(--lb-accent);\n text-size-adjust: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n &,\n *,\n ::before,\n ::after {\n box-sizing: border-box;\n transition: none var(--lb-transition-duration) var(--lb-transition-easing);\n }\n\n /* Define some variables only on first .lb-root instances */\n &:where(:not(& &)) {\n --lb-dynamic-background: var(--lb-background);\n }\n}\n\n/*************************************\n * Icon *\n *************************************/\n\n.lb-icon {\n --lb-icon-background: var(--lb-dynamic-background);\n\n inline-size: var(--lb-icon-size);\n block-size: var(--lb-icon-size);\n\n * {\n stroke-width: var(--lb-icon-weight);\n vector-effect: non-scaling-stroke;\n }\n}\n\n.lb-icon-spinner {\n transform-origin: center;\n animation: lb-animation-spin 0.75s linear infinite;\n}\n\n/*************************************\n * Button *\n *************************************/\n\n.lb-button {\n --lb-button-background: var(--lb-dynamic-background);\n\n @include button;\n\n display: flex;\n justify-content: center;\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing));\n border-radius: var(--lb-button-radius);\n background: var(--lb-button-background);\n color: var(--lb-foreground-moderate);\n\n &:where(.lb-button\\:non-disableable:disabled) {\n cursor: default;\n }\n\n &:where(:not(.lb-button\\:non-disableable):disabled) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n --lb-button-background: var(--lb-foreground-subtle);\n\n color: var(--lb-foreground-tertiary);\n }\n\n &:where(\n [data-variant=\"default\"]:not(\n :is(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n )\n )\n ) {\n background: transparent;\n }\n\n &:where([data-variant=\"primary\"]) {\n --lb-button-background: var(--lb-accent);\n\n color: var(--lb-accent-foreground);\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n --lb-button-background: var(--lb-accent-secondary);\n\n color: var(--lb-accent-foreground);\n }\n }\n\n &:where([data-variant=\"outline\"]) {\n box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle);\n transition-property: background, color, opacity, box-shadow;\n }\n}\n\n.lb-button-icon {\n --lb-icon-background: var(--lb-button-background);\n}\n\n/*************************************\n * Dropdown *\n *************************************/\n\n.lb-dropdown-item-icon {\n margin-inline-start: calc(-0.125 * var(--lb-spacing));\n margin-inline-end: calc(0.375 * var(--lb-spacing));\n color: var(--lb-foreground-moderate);\n transition-property: color;\n}\n\n.lb-dropdown-item:where(:is([data-highlighted], [data-selected])) {\n :where(.lb-dropdown-item-icon) {\n color: var(--lb-foreground-tertiary);\n }\n}\n\n/*************************************\n * Composer suggestions *\n *************************************/\n\n.lb-composer-suggestions-list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.lb-composer-suggestions-list-item {\n scroll-margin-block: $lb-elevation-list-padding;\n}\n\n/*************************************\n * Composer mention suggestions *\n *************************************/\n\n.lb-composer-mention-suggestions {\n --lb-composer-mention-suggestion-avatar-size: 1.25rem;\n}\n\n.lb-composer-mention-suggestion {\n padding: calc(0.375 * var(--lb-spacing)) calc(0.625 * var(--lb-spacing));\n}\n\n.lb-composer-mention-suggestion-avatar {\n inline-size: var(--lb-composer-mention-suggestion-avatar-size);\n margin-inline-start: calc(-0.125 * var(--lb-spacing));\n margin-inline-end: calc(0.5 * var(--lb-spacing));\n margin-block: calc(0.125 * var(--lb-spacing));\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-moderate);\n}\n\n/*************************************\n * List *\n *************************************/\n\n.lb-list {\n display: contents;\n}\n\n/*************************************\n * Emoji *\n *************************************/\n\n@include safari-only {\n .lb-emoji {\n transform: scale(0.825);\n will-change: transform;\n }\n}\n\n/*************************************\n * Emoji picker *\n *************************************/\n\n.lb-emoji-picker {\n --lb-emoji-picker-padding: $lb-emoji-picker-padding;\n --lb-emoji-picker-offset-padding: calc(\n $lb-emoji-picker-padding + 0.375 * var(--lb-spacing)\n );\n\n display: flex;\n flex-direction: column;\n block-size: 360px;\n color: var(--lb-foreground);\n}\n\n.lb-emoji-picker-header {\n flex: none;\n border-block-end: 1px solid var(--lb-foreground-subtle);\n}\n\n.lb-emoji-picker-search-container {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.lb-emoji-picker-search {\n all: unset;\n box-sizing: inherit;\n inline-size: 100%;\n padding: var(--lb-emoji-picker-offset-padding);\n padding-inline-start: calc(\n var(--lb-icon-size) + var(--lb-emoji-picker-offset-padding) + 0.375 *\n var(--lb-spacing)\n );\n background: transparent;\n outline: none;\n appearance: textfield;\n\n &::placeholder {\n color: var(--lb-foreground-moderate);\n }\n\n &::-webkit-search-cancel-button {\n display: none;\n }\n}\n\n.lb-emoji-picker-search-icon {\n position: absolute;\n inset-inline-start: var(--lb-emoji-picker-offset-padding);\n color: var(--lb-foreground-moderate);\n pointer-events: none;\n}\n\n.lb-emoji-picker-content {\n position: relative;\n flex: 1;\n}\n\n.lb-emoji-picker-loading,\n.lb-emoji-picker-empty,\n.lb-emoji-picker-error {\n position: absolute;\n inset: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.lb-emoji-picker-loading {\n color: var(--lb-foreground-moderate);\n}\n\n.lb-emoji-picker-empty,\n.lb-emoji-picker-error {\n padding: var(--lb-spacing);\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n text-align: center;\n text-wrap: balance;\n}\n\n.lb-emoji-picker-category-header {\n padding: var(--lb-emoji-picker-padding) var(--lb-emoji-picker-offset-padding);\n background: var(--lb-dynamic-background);\n}\n\n.lb-emoji-picker-category-header-title {\n color: var(--lb-foreground-tertiary);\n font-weight: 600;\n font-size: 0.675em;\n text-transform: uppercase;\n}\n\n.lb-emoji-picker-grid {\n position: absolute;\n inset: 0;\n animation: lb-animation-appear var(--lb-transition-duration)\n var(--lb-transition-easing) both;\n}\n\n.lb-emoji-picker-row {\n display: flex;\n padding-inline: var(--lb-emoji-picker-padding);\n scroll-margin-block-end: var(--lb-emoji-picker-padding);\n\n &:where([data-last]) {\n padding-block-end: var(--lb-emoji-picker-padding);\n }\n}\n\n.lb-emoji-picker-emoji {\n all: unset;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n box-sizing: inherit;\n aspect-ratio: 1;\n padding: calc(0.375 * var(--lb-spacing));\n border-radius: calc(var(--lb-radius) - 0.75 * $lb-emoji-picker-padding);\n text-align: center;\n}\n\n/*************************************\n * Tooltip *\n *************************************/\n\n.lb-tooltip {\n --lb-background: #222;\n --lb-foreground: #fff;\n --lb-foreground-contrast: 10%;\n\n position: relative;\n display: flex;\n align-items: center;\n max-inline-size: 300px;\n min-block-size: calc(\n $lb-tooltip-shortcut-height + 2 * $lb-tooltip-additional-padding\n );\n padding-inline: $lb-tooltip-horizontal-padding;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n box-shadow: var(--lb-tooltip-shadow);\n font-size: 0.75rem;\n line-height: 1;\n overflow-wrap: anywhere;\n pointer-events: none;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n z-index: 1;\n border-radius: inherit;\n box-shadow: var(--lb-inset-shadow);\n pointer-events: none;\n }\n}\n\n.lb-tooltip\\:multiline {\n justify-content: center;\n padding-block: calc(\n $lb-tooltip-vertical-padding * (1 / $lb-tooltip-line-height)\n );\n line-height: $lb-tooltip-line-height;\n text-align: center;\n}\n\n.lb-tooltip-shortcut {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n justify-content: center;\n align-items: center;\n block-size: $lb-tooltip-shortcut-height;\n margin-inline-start: $lb-tooltip-horizontal-padding;\n margin-inline-end: calc(\n -1 * $lb-tooltip-horizontal-padding + $lb-tooltip-additional-padding\n );\n padding-inline: calc(0.25 * var(--lb-spacing));\n border-radius: calc(\n var(--lb-radius) - 0.625 * $lb-tooltip-additional-padding\n );\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-tertiary);\n font-family: inherit;\n line-height: 1;\n text-transform: uppercase;\n\n :where(abbr) {\n all: unset;\n }\n}\n\n/*************************************\n * Avatar *\n *************************************/\n\n.lb-avatar {\n position: relative;\n container-type: inline-size;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n aspect-ratio: 1;\n border-radius: var(--lb-avatar-radius);\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-moderate);\n\n &:where([data-loading]) {\n background: var(--lb-foreground);\n opacity: $lb-loading-opacity;\n }\n}\n\n.lb-avatar-image {\n position: absolute;\n inset: 0;\n object-fit: cover;\n inline-size: 100%;\n block-size: 100%;\n}\n\n.lb-avatar-fallback {\n font-weight: 500;\n font-size: 35cqi;\n white-space: nowrap;\n\n /**\n * Progressive enhancement: Only show the fallback when container queries are supported\n */\n @supports not (container-type: inline-size) {\n display: none;\n }\n}\n\n/*************************************\n * Name *\n *************************************/\n\n.lb-name:where([data-loading]) {\n &::before {\n content: \"\\FEFF\";\n display: inline-block;\n vertical-align: middle;\n inline-size: 8ch;\n block-size: 1.75ex;\n border-radius: calc(0.5 * var(--lb-radius));\n background: currentcolor;\n opacity: $lb-loading-opacity;\n user-select: none;\n }\n}\n\n/*************************************\n * Loading *\n *************************************/\n\n:is(.lb-avatar, .lb-name):where([data-loading]) {\n animation: lb-animation-shimmer 8s linear infinite;\n}\n\n/*************************************\n * Body *\n *************************************/\n\n:is(.lb-comment-body, .lb-composer-editor) {\n color: var(--lb-foreground-secondary);\n\n :where(p) {\n margin-block-start: 0.25em;\n margin-block-end: 0.25em;\n\n &:where(:first-of-type) {\n margin-block-start: 0;\n }\n\n &:where(:last-of-type) {\n margin-block-end: 0;\n }\n }\n\n :where(strong) {\n font-weight: 600;\n }\n}\n\n.lb-comment-mention,\n.lb-composer-mention {\n color: var(--lb-accent);\n box-decoration-break: clone;\n font-weight: 500;\n}\n\n:is(.lb-comment-link, .lb-composer-link) {\n color: var(--lb-foreground);\n outline: none;\n font-weight: 500;\n transition-property: color, text-decoration-color;\n text-decoration-line: underline;\n text-decoration-color: var(--lb-foreground-moderate);\n text-underline-offset: 2px;\n\n &:where([href]):where(:hover, :focus-visible) {\n color: var(--lb-accent);\n text-decoration-color: var(--lb-accent-moderate);\n }\n}\n\n.lb-comment-mention:where([data-self]),\n.lb-composer-mention {\n padding: 0.1em 0.3em;\n border-radius: calc(0.675 * var(--lb-radius));\n background: var(--lb-accent-subtle);\n}\n\n/*************************************\n * Composer *\n *************************************/\n\n.lb-composer {\n position: relative;\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n transition-property: background;\n}\n\n.lb-composer-form {\n margin: 0;\n}\n\n.lb-composer:where(:has(.lb-composer-editor:not(:focus-visible))) {\n :where(.lb-button[data-variant=\"primary\"]) {\n --lb-button-background: var(--lb-foreground-subtle);\n\n color: var(--lb-foreground-tertiary);\n\n &:where(:enabled:hover, :enabled:focus-visible) {\n --lb-button-background: var(--lb-accent);\n\n color: var(--lb-accent-foreground);\n }\n }\n}\n\n.lb-composer-editor {\n padding: var(--lb-spacing);\n outline: none;\n\n :where(.lb-composer-editor-container:has(.lb-composer-attachments)) & {\n padding-block-end: calc(0.25 * var(--lb-spacing));\n }\n\n :where([data-placeholder]) {\n color: var(--lb-foreground-moderate);\n }\n}\n\n.lb-composer-mention {\n @include invisible-selection;\n\n &:where([data-selected]) {\n background: var(--lb-accent);\n color: var(--lb-accent-foreground);\n }\n}\n\n.lb-composer-footer {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n block-size: calc($lb-button-size + var(--lb-spacing));\n margin-block-start: calc(-0.125 * var(--lb-spacing));\n padding: 0 var(--lb-spacing) var(--lb-spacing);\n}\n\n.lb-composer-actions,\n.lb-composer-editor-actions {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n align-items: center;\n}\n\n.lb-composer-editor-actions {\n margin-inline-end: auto;\n}\n\n.lb-composer-attribution {\n color: var(--lb-foreground-moderate);\n outline: none;\n transition-property: color;\n\n &:where(:hover, :focus-visible) {\n color: var(--lb-foreground-tertiary);\n }\n\n :where(svg) {\n block-size: calc(0.75 * $lb-button-size);\n }\n}\n\n.lb-composer-attachments {\n padding-inline: var(--lb-spacing);\n padding-block-start: calc(0.75 * var(--lb-spacing));\n padding-block-end: var(--lb-spacing);\n}\n\n.lb-composer-editor-container:where([data-drop]) * {\n pointer-events: none;\n}\n\n.lb-composer-attachments-drop-area {\n position: absolute;\n inset: 0;\n display: flex;\n place-content: center;\n place-items: center;\n color: var(--lb-accent);\n\n &::before,\n &::after {\n content: \"\";\n position: absolute;\n inset: calc(0.5 * var(--lb-spacing));\n z-index: 0;\n border-radius: calc(0.75 * var(--lb-radius));\n }\n\n &::before {\n background: currentcolor;\n opacity: calc(1 * var(--lb-accent-contrast));\n }\n\n &::after {\n border: 2px dashed currentcolor;\n opacity: calc(2 * var(--lb-accent-contrast));\n }\n}\n\n.lb-composer-attachments-drop-area-label {\n position: relative;\n display: flex;\n gap: calc(0.25 * var(--lb-spacing));\n place-items: center;\n padding: calc(0.375 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing));\n border-radius: calc(0.75 * var(--lb-radius));\n background: var(--lb-accent);\n color: var(--lb-accent-foreground);\n font-weight: 500;\n pointer-events: none;\n}\n\n/*************************************\n * Comment *\n *************************************/\n\n.lb-comment {\n --lb-comment-avatar-size: $lb-button-size;\n\n position: relative;\n padding: var(--lb-spacing);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n font-weight: 400;\n scroll-margin: var(--lb-spacing);\n\n @media (hover: hover) {\n &:where(.lb-comment\\:show-actions-hover) {\n :where(.lb-comment-actions) {\n position: absolute;\n inset-inline-end: 0;\n opacity: 0;\n transition-property: opacity;\n }\n\n &:where(:is(:hover, :focus-within, .lb-comment\\:action-open)) {\n :where(.lb-comment-actions) {\n position: relative;\n opacity: 1;\n }\n }\n }\n }\n\n &:where(:target, [data-target]) {\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([data-editing]) {\n --lb-dynamic-background: var(--lb-background-foreground-faint);\n }\n}\n\n.lb-comment-header {\n position: relative;\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n block-size: var(--lb-comment-avatar-size);\n margin-block-end: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-details {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n min-inline-size: 0;\n}\n\n.lb-comment-avatar {\n flex: none;\n inline-size: var(--lb-comment-avatar-size);\n}\n\n.lb-comment-details-labels {\n display: flex;\n gap: calc(0.5 * var(--lb-spacing));\n align-items: baseline;\n min-inline-size: 0;\n}\n\n.lb-comment-author {\n @include truncate;\n\n font-weight: 500;\n}\n\n.lb-comment-date {\n @include truncate;\n\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-comment-date-created,\n.lb-comment-date-edited {\n display: contents;\n}\n\n.lb-comment-actions {\n display: flex;\n gap: calc(0.125 * var(--lb-spacing));\n margin-inline-start: auto;\n}\n\n.lb-comment-composer {\n margin: calc(-1 * var(--lb-spacing));\n background: unset;\n}\n\n.lb-comment-body {\n /**\n * Prevent empty lines from collapsing\n */\n :where(p span:only-child:empty)::before {\n content: \"\\FEFF\";\n user-select: none;\n }\n}\n\n.lb-comment-attachments {\n margin-block-start: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-reactions {\n display: flex;\n flex-wrap: wrap;\n gap: calc(0.375 * var(--lb-spacing));\n margin-block-start: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-comment-reaction {\n gap: calc(0.375 * var(--lb-spacing));\n block-size: $lb-button-size;\n padding-inline: calc(0.575 * var(--lb-spacing));\n border-radius: $lb-radius-full;\n\n &:where([data-self]) {\n background: var(--lb-accent-subtle);\n color: var(--lb-accent-secondary);\n box-shadow: inset 0 0 0 1px var(--lb-accent-moderate);\n\n &:where(\n :enabled:hover,\n :enabled:focus-visible,\n [aria-expanded=\"true\"],\n [aria-selected=\"true\"]\n ) {\n color: var(--lb-accent);\n }\n }\n}\n\n.lb-comment-reaction-count {\n font-weight: 500;\n font-size: 0.75em;\n font-variant-numeric: tabular-nums;\n}\n\n.lb-comment-reaction-tooltip {\n max-inline-size: 200px;\n}\n\n.lb-comment-deleted {\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-comment\\:indent-content {\n min-block-size: calc(var(--lb-comment-avatar-size) + 2 * var(--lb-spacing));\n\n :where(.lb-comment-header) {\n block-size: $lb-button-size;\n margin-block-end: calc(0.25 * var(--lb-spacing));\n }\n\n :where(.lb-comment-avatar) {\n position: absolute;\n inset-inline-start: 0;\n inset-block-start: 0;\n }\n\n :where(.lb-comment-details-labels) {\n margin-inline-start: calc(\n var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing)\n );\n }\n\n :where(.lb-comment-content) {\n padding-inline-start: calc(\n var(--lb-comment-avatar-size) + 0.75 * var(--lb-spacing)\n );\n }\n}\n\n/*************************************\n * Thread *\n *************************************/\n\n.lb-thread {\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n transition-property: background;\n\n @media (hover: hover) {\n &:where(.lb-thread\\:show-actions-hover :is(:hover, :focus-within)) {\n :where(.lb-thread-actions) {\n opacity: 1;\n }\n }\n }\n}\n\n.lb-thread-comments {\n position: relative;\n z-index: 0;\n display: flex;\n flex-direction: column;\n}\n\n.lb-thread-comment {\n z-index: 0;\n padding-block: calc(0.6 * var(--lb-spacing));\n transition-property: background;\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(var(--lb-comment-avatar-size) + var(--lb-spacing));\n }\n\n &:where(:first-of-type, [data-editing]) {\n padding-block-start: var(--lb-spacing);\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(\n var(--lb-comment-avatar-size) + 1.5 * var(--lb-spacing)\n );\n }\n }\n\n &:where(:last-of-type, [data-editing]) {\n padding-block-end: var(--lb-spacing);\n\n &:where(.lb-comment\\:indent-content) {\n min-block-size: calc(\n var(--lb-comment-avatar-size) + 1.75 * var(--lb-spacing)\n );\n }\n }\n}\n\n.lb-thread-new-indicator {\n position: relative;\n z-index: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n block-size: 0;\n\n &::before,\n &::after {\n content: \"\";\n z-index: 0;\n flex: 1;\n block-size: 0;\n border-block-start: 1px solid var(--lb-foreground-subtle);\n transition-property: border;\n }\n}\n\n.lb-thread-new-indicator-label {\n z-index: 1;\n display: flex;\n flex: none;\n gap: calc(0.325 * var(--lb-spacing));\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing)) var(--lb-spacing);\n color: var(--lb-accent);\n font-weight: 600;\n font-size: 0.675em;\n text-transform: uppercase;\n}\n\n.lb-thread-new-indicator-label-icon {\n inline-size: calc(0.6 * var(--lb-icon-size));\n block-size: calc(0.6 * var(--lb-icon-size));\n}\n\n.lb-thread-composer {\n position: relative;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n border-block-start: 1px solid var(--lb-foreground-subtle);\n pointer-events: none;\n transition-property: border;\n }\n}\n\n/*************************************\n * Attachments *\n *************************************/\n\n.lb-comment-attachments,\n.lb-composer-attachments {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));\n gap: calc(0.75 * var(--lb-spacing));\n}\n\n.lb-attachment,\n.lb-attachment-delete {\n @include button;\n}\n\n.lb-attachment {\n position: relative;\n inline-size: 100%;\n min-inline-size: 0;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n box-shadow: inset 0 0 0 1px var(--lb-foreground-subtle);\n\n &:where([tabindex=\"-1\"]) {\n cursor: default;\n }\n\n &:where(:not([tabindex=\"-1\"])) {\n &:where(:hover, :focus-visible) {\n background: var(--lb-foreground-subtle);\n }\n }\n}\n\n.lb-attachment-delete {\n position: absolute;\n inset-inline-end: -0.35rem;\n inset-block-start: -0.35rem;\n z-index: 2;\n display: flex;\n justify-content: center;\n align-items: center;\n inline-size: 1.1rem;\n block-size: 1.1rem;\n border-radius: 50%;\n background: var(--lb-foreground-subtle);\n color: var(--lb-foreground-secondary);\n box-shadow: 0 0 0 2px var(--lb-dynamic-background);\n opacity: 0;\n\n /* Invisibly increase the button's hit target size */\n &::before {\n content: \"\";\n position: absolute;\n inset: -4px;\n z-index: -1;\n border-radius: inherit;\n }\n\n &:where(:hover, :focus-visible) {\n background: var(--lb-foreground-secondary);\n color: var(--lb-dynamic-background);\n }\n\n :where(.lb-attachment:focus-within, .lb-attachment:hover) & {\n opacity: 1;\n }\n\n :where(.lb-icon) {\n inline-size: 0.75rem;\n }\n}\n\n.lb-attachment-name {\n display: flex;\n}\n\n.lb-attachment-name-base,\n.lb-attachment-description {\n @include truncate;\n}\n\n.lb-attachment-preview {\n position: relative;\n}\n\n.lb-attachment-preview-image {\n border-radius: inherit;\n transition-property: opacity;\n\n &,\n &::after,\n img {\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n }\n\n img {\n object-fit: cover;\n }\n\n &::after {\n content: \"\";\n border-radius: inherit;\n box-shadow: var(--lb-highlight-shadow);\n pointer-events: none;\n }\n\n &:where([data-hidden]) {\n opacity: 0;\n }\n}\n\n.lb-attachment-icon {\n flex: none;\n overflow: visible;\n color: var(--lb-foreground);\n}\n\n.lb-attachment-icon-glyph {\n fill: var(--lb-foreground-moderate);\n}\n\n.lb-attachment-icon-background {\n fill: var(--lb-background);\n}\n\n.lb-attachment-icon-fold {\n fill-opacity: calc(0.75 * var(--lb-foreground-contrast));\n}\n\n.lb-attachment-icon-shadow {\n filter: blur(6px);\n fill-opacity: var(--lb-foreground-contrast);\n}\n\n.lb-file-attachment {\n display: flex;\n gap: calc(0.5 * var(--lb-spacing));\n padding: calc(0.5 * var(--lb-spacing));\n padding-inline-end: calc(0.65 * var(--lb-spacing));\n\n :where(.lb-attachment-preview) {\n display: flex;\n flex: none;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n aspect-ratio: 1;\n inline-size: 2.5rem;\n border-radius: calc(0.5 * var(--lb-radius));\n background: color-mix(\n in srgb,\n transparent,\n var(--lb-foreground) var(--lb-foreground-contrast)\n );\n color: var(--lb-foreground-tertiary);\n transition-property: background, color;\n }\n\n &:where([data-error]) {\n :where(.lb-attachment-preview) {\n background: var(--lb-destructive);\n color: var(--lb-destructive-foreground);\n }\n }\n\n :where(.lb-attachment-details) {\n display: flex;\n flex-direction: column;\n gap: calc(0.25 * var(--lb-spacing));\n justify-content: center;\n min-inline-size: 0;\n font-size: 0.875em;\n }\n\n :where(.lb-attachment-name),\n :where(.lb-attachment-description) {\n transition-property: color;\n }\n\n :where(.lb-attachment-name) {\n color: var(--lb-foreground-secondary);\n font-weight: 500;\n }\n\n :where(.lb-attachment-description) {\n color: var(--lb-foreground-tertiary);\n }\n\n :where(:not([tabindex=\"-1\"])) {\n &:where(:hover, :focus-visible) {\n :where(.lb-attachment-name) {\n color: var(--lb-foreground);\n }\n\n :where(.lb-attachment-description) {\n color: var(--lb-foreground-secondary);\n }\n }\n }\n}\n\n/*************************************\n * Inbox Notification *\n *************************************/\n\n.lb-inbox-notification {\n --lb-inbox-notification-aside-size: 36px;\n\n position: relative;\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n overflow: hidden;\n padding: var(--lb-spacing);\n background: var(--lb-dynamic-background);\n color: var(--lb-foreground);\n font-weight: 400;\n text-decoration: inherit;\n transition-property: background;\n\n /* Highlight missing notifications during development */\n &:where([data-missing]) {\n --lb-accent: var(--lb-destructive) !important;\n --lb-accent-foreground: var(--lb-destructive-foreground) !important;\n --lb-accent-contrast: var(--lb-destructive-contrast) !important;\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([data-unread]) {\n --lb-dynamic-background: var(--lb-background-accent-faint);\n }\n\n &:where([href]) {\n cursor: pointer;\n\n &:where(:hover, :focus-visible, :focus-within) {\n --lb-dynamic-background: var(--lb-background-foreground-faint);\n }\n\n &:where([data-unread]) {\n &:where(:hover, :focus-visible, :focus-within) {\n --lb-dynamic-background: var(--lb-background-accent-subtle);\n }\n }\n }\n\n @media (hover: hover) {\n &:where(.lb-inbox-notification\\:show-actions-hover) {\n :where(.lb-inbox-notification-header) {\n display: grid;\n grid-template: \"title secondary\" / 1fr max-content;\n }\n\n :where(.lb-inbox-notification-details) {\n opacity: 1;\n transition-property: opacity;\n }\n\n :where(.lb-inbox-notification-actions) {\n opacity: 0;\n transition-property: opacity;\n }\n\n &:where(:is(:hover, :focus-within, .lb-inbox-notification\\:action-open)) {\n :where(.lb-inbox-notification-details) {\n opacity: 0;\n }\n\n :where(.lb-inbox-notification-actions) {\n opacity: 1;\n }\n }\n\n :where(.lb-inbox-notification-details),\n :where(.lb-inbox-notification-actions) {\n grid-area: secondary;\n justify-self: end;\n }\n }\n }\n}\n\n.lb-inbox-notification-aside {\n flex: none;\n inline-size: var(--lb-inbox-notification-aside-size);\n}\n\n.lb-inbox-notification-icon {\n display: flex;\n justify-content: center;\n place-items: center;\n aspect-ratio: 1;\n border-radius: 50%;\n background: var(--lb-foreground-subtle);\n\n .lb-inbox-notification:where([data-missing]) :where(&) {\n background: var(--lb-accent-subtle);\n color: var(--lb-accent);\n }\n}\n\n.lb-inbox-notification-content {\n flex: 1;\n}\n\n.lb-inbox-notification-content,\n.lb-inbox-notification-body {\n min-inline-size: 0;\n max-inline-size: 100%;\n}\n\n.lb-inbox-notification-header {\n display: flex;\n gap: calc(0.75 * var(--lb-spacing));\n align-items: center;\n margin-block-start: calc(0.25 * var(--lb-spacing));\n margin-block-end: calc(0.5 * var(--lb-spacing));\n}\n\n.lb-inbox-notification-title {\n min-block-size: $lb-button-size;\n\n :where(strong, .lb-list, .lb-name) {\n font-weight: 500;\n }\n}\n\n.lb-inbox-notification-details {\n flex: none;\n align-self: start;\n min-inline-size: 0;\n block-size: $lb-button-size;\n margin-inline-start: auto;\n}\n\n.lb-inbox-notification-details-labels {\n display: flex;\n align-items: baseline;\n min-inline-size: 0;\n\n &::before {\n content: \"\\FEFF\";\n }\n}\n\n.lb-inbox-notification-actions {\n display: flex;\n grid-area: actions;\n gap: calc(0.125 * var(--lb-spacing));\n align-self: start;\n}\n\n.lb-inbox-notification-comments {\n display: flex;\n flex-direction: column;\n gap: var(--lb-spacing);\n}\n\n.lb-inbox-notification-comment {\n padding: 0;\n background: transparent;\n\n :where(.lb-comment-header) {\n block-size: auto;\n color: var(--lb-foreground-tertiary);\n font-size: 0.875rem;\n }\n\n :where(.lb-comment-reaction),\n :where(.lb-comment-attachment) {\n pointer-events: none;\n }\n}\n\n.lb-inbox-notification-date {\n color: var(--lb-foreground-tertiary);\n font-size: 0.875em;\n}\n\n.lb-inbox-notification-unread-indicator {\n align-self: center;\n inline-size: 10px;\n block-size: 10px;\n margin-inline-start: calc(0.5 * var(--lb-spacing));\n border-radius: 50%;\n background: var(--lb-accent);\n}\n\n/*************************************\n * Inbox Notification List *\n *************************************/\n\n.lb-inbox-notification-list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.lb-inbox-notification-list-item {\n &:where(:not(:last-of-type)) {\n border-block-end: 1px solid var(--lb-foreground-subtle);\n }\n}\n\n/*************************************\n * Inline code *\n *************************************/\n\n:is(.lb-root) {\n :where(code) {\n padding: 0.2em 0.4em;\n border-radius: calc(0.75 * var(--lb-radius));\n background: var(--lb-foreground-subtle);\n box-decoration-break: clone;\n font-size: 85%;\n line-height: 1;\n }\n\n /**\n * Merge adjacent inline code elements\n */\n :where(span:has(code) + span code) {\n padding-inline-start: 0;\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n :where(span:has(code):has(+ span code) code) {\n padding-inline-end: 0;\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n}\n\n/* 0,0,0 specificity to inherit any styles applied to `code` elements */\n:where(:is(.lb-root) code) {\n font-family: ui-monospace, Menlo, Monaco, \"Roboto Mono\", \"Cascadia Code\",\n \"Source Code Pro\", Consolas, \"DejaVu Sans Mono\", monospace;\n}\n\n/*************************************\n * Elevation *\n *************************************/\n\n.lb-elevation {\n position: relative;\n overflow: hidden;\n border-radius: var(--lb-radius);\n background: var(--lb-dynamic-background);\n box-shadow: var(--lb-elevation-shadow);\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n z-index: 1;\n border-radius: inherit;\n box-shadow: var(--lb-inset-shadow);\n pointer-events: none;\n }\n}\n\n/*************************************\n * Elevation lists *\n *************************************/\n\n.lb-dropdown,\n.lb-composer-suggestions {\n padding: $lb-elevation-list-padding;\n}\n\n.lb-dropdown-item,\n.lb-composer-suggestions-list-item {\n display: flex;\n align-items: center;\n padding: calc(0.25 * var(--lb-spacing)) calc(0.5 * var(--lb-spacing));\n font-size: 0.875rem;\n}\n\n.lb-dropdown-item,\n.lb-composer-suggestions-list-item,\n.lb-emoji-picker-emoji {\n border-radius: calc(var(--lb-radius) - 0.75 * $lb-elevation-list-padding);\n color: var(--lb-foreground-secondary);\n outline: none;\n cursor: pointer;\n user-select: none;\n transition-property: background, color, opacity;\n}\n\n:is(\n .lb-dropdown-item,\n .lb-composer-suggestions-list-item,\n .lb-emoji-picker-emoji\n ) {\n &:where([data-highlighted], [data-selected]) {\n background: var(--lb-foreground-subtle);\n transition-duration: calc(var(--lb-transition-duration) / 2);\n }\n\n &:where(:disabled, [data-disabled]) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n}\n\n/*************************************\n * Floating animations *\n *************************************/\n\n.lb-dropdown,\n.lb-composer-suggestions,\n.lb-tooltip,\n.lb-emoji-picker {\n animation-duration: var(--lb-transition-duration);\n animation-timing-function: var(--lb-transition-easing);\n will-change: transform, opacity;\n}\n\n:is(\n .lb-dropdown,\n .lb-emoji-picker,\n .lb-tooltip:where([data-state=\"delayed-open\"]),\n .lb-composer-suggestions\n ) {\n &:where([data-side=\"top\"]) {\n animation-name: lb-animation-slide-up;\n }\n\n &:where([data-side=\"bottom\"]) {\n animation-name: lb-animation-slide-down;\n }\n}\n\n:is(.lb-dropdown, .lb-emoji-picker, .lb-tooltip, .lb-composer-suggestions) {\n &:where([data-state=\"closed\"]) {\n animation-name: lb-animation-disappear;\n }\n}\n\n@media (prefers-reduced-motion) {\n .lb-dropdown:where(:not([data-state=\"closed\"])),\n .lb-emoji-picker:where(:not([data-state=\"closed\"])),\n .lb-tooltip:where([data-state=\"delayed-open\"]:not([data-state=\"closed\"])),\n .lb-composer-suggestions:where(:not([data-state=\"closed\"])) {\n animation-name: lb-animation-appear;\n }\n}\n\n/*************************************\n * Animations *\n *************************************/\n\n@keyframes lb-animation-slide-down {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes lb-animation-slide-up {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes lb-animation-appear {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes lb-animation-disappear {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes lb-animation-shimmer {\n from,\n to {\n mask-image: linear-gradient(\n 90deg,\n rgb(0 0 0 / 50%),\n #000,\n #000,\n rgb(0 0 0 / 50%)\n );\n mask-size: 400% 100%;\n }\n\n from {\n mask-position: 200% 0;\n }\n\n to {\n mask-position: -200% 0;\n }\n}\n\n@keyframes lb-animation-spin {\n from {\n transform: rotate(0deg);\n }\n\n to {\n transform: rotate(360deg);\n }\n}\n","/* Because of `all: unset`, we have to re-define some these values. */\n@mixin button {\n all: unset;\n position: relative;\n box-sizing: inherit;\n outline: none;\n cursor: pointer;\n user-select: none;\n transition-timing-function: var(--lb-transition-easing);\n transition-duration: var(--lb-transition-duration);\n transition-property: background, color, opacity;\n -webkit-tap-highlight-color: transparent;\n\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n transition-property: box-shadow;\n }\n\n &:where(:focus-visible) {\n z-index: 1;\n\n &::after {\n box-shadow:\n var(--lb-dynamic-background) 0 0 0 2px,\n var(--lb-accent) 0 0 0 4px;\n }\n }\n}\n\n@mixin truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@mixin invisible-selection {\n &::selection,\n *::selection {\n background: transparent;\n }\n}\n\n@mixin invisible-scrollbar {\n & {\n -ms-overflow-style: none;\n scrollbar-width: none;\n }\n\n &::-webkit-scrollbar {\n display: none;\n }\n}\n\n@mixin firefox-only {\n @supports (-moz-appearance: none) {\n @content;\n }\n}\n\n@mixin not-firefox {\n @supports not (-moz-appearance: none) {\n @content;\n }\n}\n\n@mixin safari-only {\n @supports (background: -webkit-named-image(i)) {\n @content;\n }\n}\n\n@mixin not-safari {\n @supports not (background: -webkit-named-image(i)) {\n @content;\n }\n}\n"]}
|