@liveblocks/react-ui 3.0.0 → 3.1.0-alpha1

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.
Files changed (126) hide show
  1. package/dist/_private/index.cjs +4 -0
  2. package/dist/_private/index.cjs.map +1 -1
  3. package/dist/_private/index.d.cts +15 -2
  4. package/dist/_private/index.d.ts +15 -2
  5. package/dist/_private/index.js +2 -0
  6. package/dist/_private/index.js.map +1 -1
  7. package/dist/components/AiChat.cjs +2 -2
  8. package/dist/components/AiChat.cjs.map +1 -1
  9. package/dist/components/AiChat.js +2 -2
  10. package/dist/components/AiChat.js.map +1 -1
  11. package/dist/components/AiTool.cjs +9 -7
  12. package/dist/components/AiTool.cjs.map +1 -1
  13. package/dist/components/AiTool.js +9 -7
  14. package/dist/components/AiTool.js.map +1 -1
  15. package/dist/components/Comment.cjs +10 -10
  16. package/dist/components/Comment.cjs.map +1 -1
  17. package/dist/components/Comment.js +10 -10
  18. package/dist/components/Comment.js.map +1 -1
  19. package/dist/components/Composer.cjs +7 -10
  20. package/dist/components/Composer.cjs.map +1 -1
  21. package/dist/components/Composer.js +7 -10
  22. package/dist/components/Composer.js.map +1 -1
  23. package/dist/components/HistoryVersionSummary.cjs +2 -2
  24. package/dist/components/HistoryVersionSummary.cjs.map +1 -1
  25. package/dist/components/HistoryVersionSummary.js +2 -2
  26. package/dist/components/HistoryVersionSummary.js.map +1 -1
  27. package/dist/components/HistoryVersionSummaryList.cjs +2 -5
  28. package/dist/components/HistoryVersionSummaryList.cjs.map +1 -1
  29. package/dist/components/HistoryVersionSummaryList.js +2 -5
  30. package/dist/components/HistoryVersionSummaryList.js.map +1 -1
  31. package/dist/components/InboxNotification.cjs +4 -4
  32. package/dist/components/InboxNotification.cjs.map +1 -1
  33. package/dist/components/InboxNotification.js +4 -4
  34. package/dist/components/InboxNotification.js.map +1 -1
  35. package/dist/components/InboxNotificationList.cjs +2 -2
  36. package/dist/components/InboxNotificationList.cjs.map +1 -1
  37. package/dist/components/InboxNotificationList.js +2 -2
  38. package/dist/components/InboxNotificationList.js.map +1 -1
  39. package/dist/components/Thread.cjs +2 -2
  40. package/dist/components/Thread.cjs.map +1 -1
  41. package/dist/components/Thread.js +2 -2
  42. package/dist/components/Thread.js.map +1 -1
  43. package/dist/components/internal/AiChatAssistantMessage.cjs +9 -4
  44. package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
  45. package/dist/components/internal/AiChatAssistantMessage.js +10 -5
  46. package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
  47. package/dist/components/internal/AiChatComposer.cjs +2 -2
  48. package/dist/components/internal/AiChatComposer.cjs.map +1 -1
  49. package/dist/components/internal/AiChatComposer.js +2 -2
  50. package/dist/components/internal/AiChatComposer.js.map +1 -1
  51. package/dist/components/internal/AiChatUserMessage.cjs +2 -2
  52. package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
  53. package/dist/components/internal/AiChatUserMessage.js +2 -2
  54. package/dist/components/internal/AiChatUserMessage.js.map +1 -1
  55. package/dist/components/internal/Attachment.cjs +3 -3
  56. package/dist/components/internal/Attachment.cjs.map +1 -1
  57. package/dist/components/internal/Attachment.js +3 -3
  58. package/dist/components/internal/Attachment.js.map +1 -1
  59. package/dist/components/internal/Attribution.cjs +2 -2
  60. package/dist/components/internal/Attribution.cjs.map +1 -1
  61. package/dist/components/internal/Attribution.js +2 -2
  62. package/dist/components/internal/Attribution.js.map +1 -1
  63. package/dist/components/internal/Avatar.cjs +2 -2
  64. package/dist/components/internal/Avatar.cjs.map +1 -1
  65. package/dist/components/internal/Avatar.js +2 -2
  66. package/dist/components/internal/Avatar.js.map +1 -1
  67. package/dist/components/internal/Button.cjs +3 -3
  68. package/dist/components/internal/Button.cjs.map +1 -1
  69. package/dist/components/internal/Button.js +3 -3
  70. package/dist/components/internal/Button.js.map +1 -1
  71. package/dist/components/internal/Dropdown.cjs +3 -3
  72. package/dist/components/internal/Dropdown.cjs.map +1 -1
  73. package/dist/components/internal/Dropdown.js +3 -3
  74. package/dist/components/internal/Dropdown.js.map +1 -1
  75. package/dist/components/internal/Emoji.cjs +2 -2
  76. package/dist/components/internal/Emoji.cjs.map +1 -1
  77. package/dist/components/internal/Emoji.js +2 -2
  78. package/dist/components/internal/Emoji.js.map +1 -1
  79. package/dist/components/internal/EmojiPicker.cjs +5 -5
  80. package/dist/components/internal/EmojiPicker.cjs.map +1 -1
  81. package/dist/components/internal/EmojiPicker.js +5 -5
  82. package/dist/components/internal/EmojiPicker.js.map +1 -1
  83. package/dist/components/internal/Icon.cjs +2 -2
  84. package/dist/components/internal/Icon.cjs.map +1 -1
  85. package/dist/components/internal/Icon.js +2 -2
  86. package/dist/components/internal/Icon.js.map +1 -1
  87. package/dist/components/internal/InboxNotificationThread.cjs +2 -2
  88. package/dist/components/internal/InboxNotificationThread.cjs.map +1 -1
  89. package/dist/components/internal/InboxNotificationThread.js +2 -2
  90. package/dist/components/internal/InboxNotificationThread.js.map +1 -1
  91. package/dist/components/internal/List.cjs +2 -2
  92. package/dist/components/internal/List.cjs.map +1 -1
  93. package/dist/components/internal/List.js +2 -2
  94. package/dist/components/internal/List.js.map +1 -1
  95. package/dist/components/internal/Prose.cjs +2 -2
  96. package/dist/components/internal/Prose.cjs.map +1 -1
  97. package/dist/components/internal/Prose.js +2 -2
  98. package/dist/components/internal/Prose.js.map +1 -1
  99. package/dist/components/internal/Room.cjs +2 -2
  100. package/dist/components/internal/Room.cjs.map +1 -1
  101. package/dist/components/internal/Room.js +2 -2
  102. package/dist/components/internal/Room.js.map +1 -1
  103. package/dist/components/internal/Tooltip.cjs +2 -2
  104. package/dist/components/internal/Tooltip.cjs.map +1 -1
  105. package/dist/components/internal/Tooltip.js +2 -2
  106. package/dist/components/internal/Tooltip.js.map +1 -1
  107. package/dist/components/internal/User.cjs +2 -2
  108. package/dist/components/internal/User.cjs.map +1 -1
  109. package/dist/components/internal/User.js +2 -2
  110. package/dist/components/internal/User.js.map +1 -1
  111. package/dist/index.d.cts +6 -0
  112. package/dist/index.d.ts +6 -0
  113. package/dist/utils/{class-names.cjs → cn.cjs} +3 -3
  114. package/dist/utils/cn.cjs.map +1 -0
  115. package/dist/utils/{class-names.js → cn.js} +3 -3
  116. package/dist/utils/cn.js.map +1 -0
  117. package/dist/version.cjs +1 -1
  118. package/dist/version.cjs.map +1 -1
  119. package/dist/version.js +1 -1
  120. package/dist/version.js.map +1 -1
  121. package/package.json +4 -4
  122. package/src/styles/index.css +4 -3
  123. package/styles.css +1 -1
  124. package/styles.css.map +1 -1
  125. package/dist/utils/class-names.cjs.map +0 -1
  126. package/dist/utils/class-names.js.map +0 -1
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { memo, forwardRef } from 'react';
3
3
  import '../../_private/index.js';
4
4
  import { useOverrides } from '../../overrides.js';
5
- import { classNames } from '../../utils/class-names.js';
5
+ import { cn } from '../../utils/cn.js';
6
6
  import { Content as AiMessageContent } from '../../primitives/AiMessage/index.js';
7
7
 
8
8
  function PlainTextPart({ part }) {
@@ -16,7 +16,7 @@ const AiChatUserMessage = memo(
16
16
  const $ = useOverrides(overrides);
17
17
  return /* @__PURE__ */ jsx("div", {
18
18
  ref: forwardedRef,
19
- className: classNames(
19
+ className: cn(
20
20
  "lb-ai-chat-message lb-ai-chat-user-message",
21
21
  className
22
22
  ),
@@ -1 +1 @@
1
- {"version":3,"file":"AiChatUserMessage.js","sources":["../../../src/components/internal/AiChatUserMessage.tsx"],"sourcesContent":["import type {\n AiTextPart,\n AiUserMessage,\n WithNavigation,\n} from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport { forwardRef, memo } from \"react\";\n\nimport { AiMessage } from \"../../_private\";\nimport { type GlobalOverrides, useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\ntype UiUserMessage = WithNavigation<AiUserMessage>;\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatUserMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatUserMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiUserMessage;\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides>;\n}\n\ntype PlainTextPartProps = {\n part: AiTextPart;\n};\n\nfunction PlainTextPart({ part }: PlainTextPartProps) {\n return <p>{part.text}</p>;\n}\n\nexport const AiChatUserMessage = memo(\n forwardRef<HTMLDivElement, AiChatUserMessageProps>(\n ({ message, className, overrides }, forwardedRef) => {\n const $ = useOverrides(overrides);\n return (\n <div\n ref={forwardedRef}\n className={classNames(\n \"lb-ai-chat-message lb-ai-chat-user-message\",\n className\n )}\n >\n {message.deletedAt !== undefined ? (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n ) : (\n <div className=\"lb-ai-chat-message-content\">\n <AiMessage.Content\n message={message}\n components={{\n TextPart: PlainTextPart,\n }}\n className=\"lb-prose lb-ai-chat-message-text\"\n />\n </div>\n )}\n </div>\n );\n }\n )\n);\n"],"names":["AiMessage.Content"],"mappings":";;;;;;;AAgCA,SAAS,aAAA,CAAc,EAAE,IAAA,EAA4B,EAAA;AACnD,EAAA,uBAAQ,GAAA,CAAA,GAAA,EAAA;AAAA,IAAG,QAAK,EAAA,IAAA,CAAA,IAAA;AAAA,GAAK,CAAA,CAAA;AACvB,CAAA;AAEO,MAAM,iBAAoB,GAAA,IAAA;AAAA,EAC/B,UAAA;AAAA,IACE,CAAC,EAAE,OAAA,EAAS,SAAW,EAAA,SAAA,IAAa,YAAiB,KAAA;AACnD,MAAM,MAAA,CAAA,GAAI,aAAa,SAAS,CAAA,CAAA;AAChC,MAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,QACC,GAAK,EAAA,YAAA;AAAA,QACL,SAAW,EAAA,UAAA;AAAA,UACT,4CAAA;AAAA,UACA,SAAA;AAAA,SACF;AAAA,QAEC,QAAA,EAAA,OAAA,CAAQ,SAAc,KAAA,KAAA,CAAA,mBACpB,GAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,4BAAA;AAAA,UACZ,QAAE,EAAA,CAAA,CAAA,uBAAA;AAAA,SACL,oBAEC,GAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,4BAAA;AAAA,UACb,QAAA,kBAAA,GAAA,CAACA,gBAAA,EAAA;AAAA,YACC,OAAA;AAAA,YACA,UAAY,EAAA;AAAA,cACV,QAAU,EAAA,aAAA;AAAA,aACZ;AAAA,YACA,SAAU,EAAA,kCAAA;AAAA,WACZ,CAAA;AAAA,SACF,CAAA;AAAA,OAEJ,CAAA,CAAA;AAAA,KAEJ;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"AiChatUserMessage.js","sources":["../../../src/components/internal/AiChatUserMessage.tsx"],"sourcesContent":["import type {\n AiTextPart,\n AiUserMessage,\n WithNavigation,\n} from \"@liveblocks/core\";\nimport type { ComponentProps } from \"react\";\nimport { forwardRef, memo } from \"react\";\n\nimport { AiMessage } from \"../../_private\";\nimport { type GlobalOverrides, useOverrides } from \"../../overrides\";\nimport { cn } from \"../../utils/cn\";\n\ntype UiUserMessage = WithNavigation<AiUserMessage>;\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatUserMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatUserMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiUserMessage;\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides>;\n}\n\ntype PlainTextPartProps = {\n part: AiTextPart;\n};\n\nfunction PlainTextPart({ part }: PlainTextPartProps) {\n return <p>{part.text}</p>;\n}\n\nexport const AiChatUserMessage = memo(\n forwardRef<HTMLDivElement, AiChatUserMessageProps>(\n ({ message, className, overrides }, forwardedRef) => {\n const $ = useOverrides(overrides);\n return (\n <div\n ref={forwardedRef}\n className={cn(\n \"lb-ai-chat-message lb-ai-chat-user-message\",\n className\n )}\n >\n {message.deletedAt !== undefined ? (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n ) : (\n <div className=\"lb-ai-chat-message-content\">\n <AiMessage.Content\n message={message}\n components={{\n TextPart: PlainTextPart,\n }}\n className=\"lb-prose lb-ai-chat-message-text\"\n />\n </div>\n )}\n </div>\n );\n }\n )\n);\n"],"names":["AiMessage.Content"],"mappings":";;;;;;;AAgCA,SAAS,aAAA,CAAc,EAAE,IAAA,EAA4B,EAAA;AACnD,EAAA,uBAAQ,GAAA,CAAA,GAAA,EAAA;AAAA,IAAG,QAAK,EAAA,IAAA,CAAA,IAAA;AAAA,GAAK,CAAA,CAAA;AACvB,CAAA;AAEO,MAAM,iBAAoB,GAAA,IAAA;AAAA,EAC/B,UAAA;AAAA,IACE,CAAC,EAAE,OAAA,EAAS,SAAW,EAAA,SAAA,IAAa,YAAiB,KAAA;AACnD,MAAM,MAAA,CAAA,GAAI,aAAa,SAAS,CAAA,CAAA;AAChC,MAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,QACC,GAAK,EAAA,YAAA;AAAA,QACL,SAAW,EAAA,EAAA;AAAA,UACT,4CAAA;AAAA,UACA,SAAA;AAAA,SACF;AAAA,QAEC,QAAA,EAAA,OAAA,CAAQ,SAAc,KAAA,KAAA,CAAA,mBACpB,GAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,4BAAA;AAAA,UACZ,QAAE,EAAA,CAAA,CAAA,uBAAA;AAAA,SACL,oBAEC,GAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,4BAAA;AAAA,UACb,QAAA,kBAAA,GAAA,CAACA,gBAAA,EAAA;AAAA,YACC,OAAA;AAAA,YACA,UAAY,EAAA;AAAA,cACV,QAAU,EAAA,aAAA;AAAA,aACZ;AAAA,YACA,SAAU,EAAA,kCAAA;AAAA,WACZ,CAAA;AAAA,SACF,CAAA;AAAA,OAEJ,CAAA,CAAA;AAAA,KAEJ;AAAA,GACF;AACF;;;;"}
@@ -10,7 +10,7 @@ var Warning = require('../../icons/Warning.cjs');
10
10
  var overrides = require('../../overrides.cjs');
11
11
  require('../../primitives/index.cjs');
12
12
  var contexts = require('../../primitives/Composer/contexts.cjs');
13
- var classNames = require('../../utils/class-names.cjs');
13
+ var cn = require('../../utils/cn.cjs');
14
14
  var formatFileSize = require('../../utils/format-file-size.cjs');
15
15
  var Tooltip = require('./Tooltip.cjs');
16
16
  var utils = require('../../primitives/Composer/utils.cjs');
@@ -259,7 +259,7 @@ function MediaAttachment({
259
259
  );
260
260
  const handleKeyDown = useClickOnKeyDown(onKeyDown);
261
261
  return /* @__PURE__ */ jsxRuntime.jsxs("div", {
262
- className: classNames.classNames("lb-attachment lb-media-attachment", className),
262
+ className: cn.cn("lb-attachment lb-media-attachment", className),
263
263
  "data-error": isError ? "" : void 0,
264
264
  ...props,
265
265
  role: onClick ? "button" : void 0,
@@ -325,7 +325,7 @@ function FileAttachment({
325
325
  );
326
326
  const handleKeyDown = useClickOnKeyDown(onKeyDown);
327
327
  return /* @__PURE__ */ jsxRuntime.jsxs("div", {
328
- className: classNames.classNames("lb-attachment lb-file-attachment", className),
328
+ className: cn.cn("lb-attachment lb-file-attachment", className),
329
329
  "data-error": isError ? "" : void 0,
330
330
  ...props,
331
331
  role: onClick ? "button" : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"Attachment.cjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } 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\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\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 getAttachmentIconGlyph(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 AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\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 AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\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\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\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 [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\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 if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\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 return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAuBA;AAWA;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;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACqE;AACzC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;;;"}
1
+ {"version":3,"file":"Attachment.cjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { cn } from \"../../utils/cn\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\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 getAttachmentIconGlyph(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 AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\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 AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\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\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\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 [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\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 if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\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 return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={cn(\"lb-attachment lb-media-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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={cn(\"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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAuBA;AAWA;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;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AAC6D;AACjC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AAC4D;AAChC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;;;"}
@@ -8,7 +8,7 @@ import { WarningIcon } from '../../icons/Warning.js';
8
8
  import { useOverrides } from '../../overrides.js';
9
9
  import '../../primitives/index.js';
10
10
  import { useComposerAttachmentsContextOrNull } from '../../primitives/Composer/contexts.js';
11
- import { classNames } from '../../utils/class-names.js';
11
+ import { cn } from '../../utils/cn.js';
12
12
  import { formatFileSize } from '../../utils/format-file-size.js';
13
13
  import { Tooltip } from './Tooltip.js';
14
14
  import { AttachmentTooLargeError } from '../../primitives/Composer/utils.js';
@@ -257,7 +257,7 @@ function MediaAttachment({
257
257
  );
258
258
  const handleKeyDown = useClickOnKeyDown(onKeyDown);
259
259
  return /* @__PURE__ */ jsxs("div", {
260
- className: classNames("lb-attachment lb-media-attachment", className),
260
+ className: cn("lb-attachment lb-media-attachment", className),
261
261
  "data-error": isError ? "" : void 0,
262
262
  ...props,
263
263
  role: onClick ? "button" : void 0,
@@ -323,7 +323,7 @@ function FileAttachment({
323
323
  );
324
324
  const handleKeyDown = useClickOnKeyDown(onKeyDown);
325
325
  return /* @__PURE__ */ jsxs("div", {
326
- className: classNames("lb-attachment lb-file-attachment", className),
326
+ className: cn("lb-attachment lb-file-attachment", className),
327
327
  "data-error": isError ? "" : void 0,
328
328
  ...props,
329
329
  role: onClick ? "button" : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } 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\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\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 getAttachmentIconGlyph(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 AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\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 AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\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\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\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 [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\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 if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\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 return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAuBA;AAWA;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;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACqE;AACzC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;"}
1
+ {"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { cn } from \"../../utils/cn\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\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 getAttachmentIconGlyph(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 AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\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 AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\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\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\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 [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\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 if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\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 return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={cn(\"lb-attachment lb-media-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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={cn(\"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 <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\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\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAuBA;AAWA;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;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AAC6D;AACjC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AAC4D;AAChC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;"}
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var classNames = require('../../utils/class-names.cjs');
4
+ var cn = require('../../utils/cn.cjs');
5
5
 
6
6
  function Attribution({ className, ...props }) {
7
7
  return /* @__PURE__ */ jsxRuntime.jsx("a", {
8
8
  href: "https://liveblocks.io",
9
9
  target: "_blank",
10
10
  rel: "noopener noreferrer",
11
- className: classNames.classNames("lb-composer-attribution", className),
11
+ className: cn.cn("lb-composer-attribution", className),
12
12
  ...props,
13
13
  children: /* @__PURE__ */ jsxRuntime.jsx("svg", {
14
14
  xmlns: "http://www.w3.org/2000/svg",
@@ -1 +1 @@
1
- {"version":3,"file":"Attribution.cjs","sources":["../../../src/components/internal/Attribution.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport function Attribution({ className, ...props }: ComponentProps<\"a\">) {\n return (\n <a\n href=\"https://liveblocks.io\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={classNames(\"lb-composer-attribution\", className)}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 72\"\n aria-label=\"Made with Liveblocks\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M86 10h-8v50h8V10Zm16 14h-8v36h8V24Zm0-15h-8v9h8V9Zm13 15h-9l12 36h10l13-36h-9l-9 28-8-28Zm44-1c-11 0-18 8-18 19s7 19 18 19c8 0 15-4 17-13h-8c-1 4-5 6-9 6-6 0-9-3-9-10h27c0-10-6-21-18-21Zm0 7c5 0 9 3 9 8h-18c0-5 4-8 9-8Zm42-7c-4 0-8 2-11 6V10h-8v50h8v-5c3 4 7 6 11 6 11 0 16-9 16-19s-5-19-16-19Zm-2 32c-7 0-9-7-9-13s2-13 9-13 9 7 9 13-2 13-9 13Zm32-45h-8v50h8V10Zm24 51c11 0 18-8 18-19s-8-19-18-19c-11 0-19 8-19 19s7 19 19 19Zm0-6c-8 0-10-7-10-13s2-13 10-13c7 0 9 7 9 13s-2 13-9 13Zm39 6c8 0 15-4 17-12l-8-1c-2 4-4 6-9 6-7 0-9-6-9-12s2-12 9-12c5 0 8 3 8 7l9-1c-2-8-9-13-17-13-11 0-18 9-18 19 0 11 7 19 18 19Zm30-14 4-4 10 17h10l-15-23 15-13h-11l-13 13V10h-9v50h9V47Zm39 14c8 0 16-3 16-12 0-8-8-10-15-11-2-1-7-1-7-5 0-3 3-4 6-4 4 0 7 3 7 7l8-1c-1-9-8-12-15-12s-15 3-15 11 9 10 15 11c3 1 8 2 8 5 0 4-4 5-7 5-5 0-8-3-9-7l-8 1c1 8 9 12 16 12ZM41 27H0l12 12v17l29-29ZM20 60h40L48 48V32L20 60Z\"\n fill=\"currentColor\"\n />\n </svg>\n </a>\n );\n}\n"],"names":["jsx","classNames"],"mappings":";;;;;AAIO,SAAS,WAAY,CAAA,EAAE,SAAc,EAAA,GAAA,KAAA,EAA8B,EAAA;AACxE,EAAA,uBACGA,cAAA,CAAA,GAAA,EAAA;AAAA,IACC,IAAK,EAAA,uBAAA;AAAA,IACL,MAAO,EAAA,QAAA;AAAA,IACP,GAAI,EAAA,qBAAA;AAAA,IACJ,SAAA,EAAWC,qBAAW,CAAA,yBAAA,EAA2B,SAAS,CAAA;AAAA,IACzD,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAAD,cAAA,CAAA,KAAA,EAAA;AAAA,MACC,KAAM,EAAA,4BAAA;AAAA,MACN,OAAQ,EAAA,YAAA;AAAA,MACR,YAAW,EAAA,sBAAA;AAAA,MAEX,QAAC,kBAAAA,cAAA,CAAA,MAAA,EAAA;AAAA,QACC,QAAS,EAAA,SAAA;AAAA,QACT,QAAS,EAAA,SAAA;AAAA,QACT,CAAE,EAAA,y3BAAA;AAAA,QACF,IAAK,EAAA,cAAA;AAAA,OACP,CAAA;AAAA,KACF,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Attribution.cjs","sources":["../../../src/components/internal/Attribution.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\nexport function Attribution({ className, ...props }: ComponentProps<\"a\">) {\n return (\n <a\n href=\"https://liveblocks.io\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\"lb-composer-attribution\", className)}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 72\"\n aria-label=\"Made with Liveblocks\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M86 10h-8v50h8V10Zm16 14h-8v36h8V24Zm0-15h-8v9h8V9Zm13 15h-9l12 36h10l13-36h-9l-9 28-8-28Zm44-1c-11 0-18 8-18 19s7 19 18 19c8 0 15-4 17-13h-8c-1 4-5 6-9 6-6 0-9-3-9-10h27c0-10-6-21-18-21Zm0 7c5 0 9 3 9 8h-18c0-5 4-8 9-8Zm42-7c-4 0-8 2-11 6V10h-8v50h8v-5c3 4 7 6 11 6 11 0 16-9 16-19s-5-19-16-19Zm-2 32c-7 0-9-7-9-13s2-13 9-13 9 7 9 13-2 13-9 13Zm32-45h-8v50h8V10Zm24 51c11 0 18-8 18-19s-8-19-18-19c-11 0-19 8-19 19s7 19 19 19Zm0-6c-8 0-10-7-10-13s2-13 10-13c7 0 9 7 9 13s-2 13-9 13Zm39 6c8 0 15-4 17-12l-8-1c-2 4-4 6-9 6-7 0-9-6-9-12s2-12 9-12c5 0 8 3 8 7l9-1c-2-8-9-13-17-13-11 0-18 9-18 19 0 11 7 19 18 19Zm30-14 4-4 10 17h10l-15-23 15-13h-11l-13 13V10h-9v50h9V47Zm39 14c8 0 16-3 16-12 0-8-8-10-15-11-2-1-7-1-7-5 0-3 3-4 6-4 4 0 7 3 7 7l8-1c-1-9-8-12-15-12s-15 3-15 11 9 10 15 11c3 1 8 2 8 5 0 4-4 5-7 5-5 0-8-3-9-7l-8 1c1 8 9 12 16 12ZM41 27H0l12 12v17l29-29ZM20 60h40L48 48V32L20 60Z\"\n fill=\"currentColor\"\n />\n </svg>\n </a>\n );\n}\n"],"names":["jsx","cn"],"mappings":";;;;;AAIO,SAAS,WAAY,CAAA,EAAE,SAAc,EAAA,GAAA,KAAA,EAA8B,EAAA;AACxE,EAAA,uBACGA,cAAA,CAAA,GAAA,EAAA;AAAA,IACC,IAAK,EAAA,uBAAA;AAAA,IACL,MAAO,EAAA,QAAA;AAAA,IACP,GAAI,EAAA,qBAAA;AAAA,IACJ,SAAA,EAAWC,KAAG,CAAA,yBAAA,EAA2B,SAAS,CAAA;AAAA,IACjD,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAAD,cAAA,CAAA,KAAA,EAAA;AAAA,MACC,KAAM,EAAA,4BAAA;AAAA,MACN,OAAQ,EAAA,YAAA;AAAA,MACR,YAAW,EAAA,sBAAA;AAAA,MAEX,QAAC,kBAAAA,cAAA,CAAA,MAAA,EAAA;AAAA,QACC,QAAS,EAAA,SAAA;AAAA,QACT,QAAS,EAAA,SAAA;AAAA,QACT,CAAE,EAAA,y3BAAA;AAAA,QACF,IAAK,EAAA,cAAA;AAAA,OACP,CAAA;AAAA,KACF,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ;;;;"}
@@ -1,12 +1,12 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { classNames } from '../../utils/class-names.js';
2
+ import { cn } from '../../utils/cn.js';
3
3
 
4
4
  function Attribution({ className, ...props }) {
5
5
  return /* @__PURE__ */ jsx("a", {
6
6
  href: "https://liveblocks.io",
7
7
  target: "_blank",
8
8
  rel: "noopener noreferrer",
9
- className: classNames("lb-composer-attribution", className),
9
+ className: cn("lb-composer-attribution", className),
10
10
  ...props,
11
11
  children: /* @__PURE__ */ jsx("svg", {
12
12
  xmlns: "http://www.w3.org/2000/svg",
@@ -1 +1 @@
1
- {"version":3,"file":"Attribution.js","sources":["../../../src/components/internal/Attribution.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport function Attribution({ className, ...props }: ComponentProps<\"a\">) {\n return (\n <a\n href=\"https://liveblocks.io\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={classNames(\"lb-composer-attribution\", className)}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 72\"\n aria-label=\"Made with Liveblocks\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M86 10h-8v50h8V10Zm16 14h-8v36h8V24Zm0-15h-8v9h8V9Zm13 15h-9l12 36h10l13-36h-9l-9 28-8-28Zm44-1c-11 0-18 8-18 19s7 19 18 19c8 0 15-4 17-13h-8c-1 4-5 6-9 6-6 0-9-3-9-10h27c0-10-6-21-18-21Zm0 7c5 0 9 3 9 8h-18c0-5 4-8 9-8Zm42-7c-4 0-8 2-11 6V10h-8v50h8v-5c3 4 7 6 11 6 11 0 16-9 16-19s-5-19-16-19Zm-2 32c-7 0-9-7-9-13s2-13 9-13 9 7 9 13-2 13-9 13Zm32-45h-8v50h8V10Zm24 51c11 0 18-8 18-19s-8-19-18-19c-11 0-19 8-19 19s7 19 19 19Zm0-6c-8 0-10-7-10-13s2-13 10-13c7 0 9 7 9 13s-2 13-9 13Zm39 6c8 0 15-4 17-12l-8-1c-2 4-4 6-9 6-7 0-9-6-9-12s2-12 9-12c5 0 8 3 8 7l9-1c-2-8-9-13-17-13-11 0-18 9-18 19 0 11 7 19 18 19Zm30-14 4-4 10 17h10l-15-23 15-13h-11l-13 13V10h-9v50h9V47Zm39 14c8 0 16-3 16-12 0-8-8-10-15-11-2-1-7-1-7-5 0-3 3-4 6-4 4 0 7 3 7 7l8-1c-1-9-8-12-15-12s-15 3-15 11 9 10 15 11c3 1 8 2 8 5 0 4-4 5-7 5-5 0-8-3-9-7l-8 1c1 8 9 12 16 12ZM41 27H0l12 12v17l29-29ZM20 60h40L48 48V32L20 60Z\"\n fill=\"currentColor\"\n />\n </svg>\n </a>\n );\n}\n"],"names":[],"mappings":";;;AAIO,SAAS,WAAY,CAAA,EAAE,SAAc,EAAA,GAAA,KAAA,EAA8B,EAAA;AACxE,EAAA,uBACG,GAAA,CAAA,GAAA,EAAA;AAAA,IACC,IAAK,EAAA,uBAAA;AAAA,IACL,MAAO,EAAA,QAAA;AAAA,IACP,GAAI,EAAA,qBAAA;AAAA,IACJ,SAAA,EAAW,UAAW,CAAA,yBAAA,EAA2B,SAAS,CAAA;AAAA,IACzD,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA;AAAA,MACC,KAAM,EAAA,4BAAA;AAAA,MACN,OAAQ,EAAA,YAAA;AAAA,MACR,YAAW,EAAA,sBAAA;AAAA,MAEX,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA;AAAA,QACC,QAAS,EAAA,SAAA;AAAA,QACT,QAAS,EAAA,SAAA;AAAA,QACT,CAAE,EAAA,y3BAAA;AAAA,QACF,IAAK,EAAA,cAAA;AAAA,OACP,CAAA;AAAA,KACF,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Attribution.js","sources":["../../../src/components/internal/Attribution.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\nexport function Attribution({ className, ...props }: ComponentProps<\"a\">) {\n return (\n <a\n href=\"https://liveblocks.io\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\"lb-composer-attribution\", className)}\n {...props}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 384 72\"\n aria-label=\"Made with Liveblocks\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M86 10h-8v50h8V10Zm16 14h-8v36h8V24Zm0-15h-8v9h8V9Zm13 15h-9l12 36h10l13-36h-9l-9 28-8-28Zm44-1c-11 0-18 8-18 19s7 19 18 19c8 0 15-4 17-13h-8c-1 4-5 6-9 6-6 0-9-3-9-10h27c0-10-6-21-18-21Zm0 7c5 0 9 3 9 8h-18c0-5 4-8 9-8Zm42-7c-4 0-8 2-11 6V10h-8v50h8v-5c3 4 7 6 11 6 11 0 16-9 16-19s-5-19-16-19Zm-2 32c-7 0-9-7-9-13s2-13 9-13 9 7 9 13-2 13-9 13Zm32-45h-8v50h8V10Zm24 51c11 0 18-8 18-19s-8-19-18-19c-11 0-19 8-19 19s7 19 19 19Zm0-6c-8 0-10-7-10-13s2-13 10-13c7 0 9 7 9 13s-2 13-9 13Zm39 6c8 0 15-4 17-12l-8-1c-2 4-4 6-9 6-7 0-9-6-9-12s2-12 9-12c5 0 8 3 8 7l9-1c-2-8-9-13-17-13-11 0-18 9-18 19 0 11 7 19 18 19Zm30-14 4-4 10 17h10l-15-23 15-13h-11l-13 13V10h-9v50h9V47Zm39 14c8 0 16-3 16-12 0-8-8-10-15-11-2-1-7-1-7-5 0-3 3-4 6-4 4 0 7 3 7 7l8-1c-1-9-8-12-15-12s-15 3-15 11 9 10 15 11c3 1 8 2 8 5 0 4-4 5-7 5-5 0-8-3-9-7l-8 1c1 8 9 12 16 12ZM41 27H0l12 12v17l29-29ZM20 60h40L48 48V32L20 60Z\"\n fill=\"currentColor\"\n />\n </svg>\n </a>\n );\n}\n"],"names":[],"mappings":";;;AAIO,SAAS,WAAY,CAAA,EAAE,SAAc,EAAA,GAAA,KAAA,EAA8B,EAAA;AACxE,EAAA,uBACG,GAAA,CAAA,GAAA,EAAA;AAAA,IACC,IAAK,EAAA,uBAAA;AAAA,IACL,MAAO,EAAA,QAAA;AAAA,IACP,GAAI,EAAA,qBAAA;AAAA,IACJ,SAAA,EAAW,EAAG,CAAA,yBAAA,EAA2B,SAAS,CAAA;AAAA,IACjD,GAAG,KAAA;AAAA,IAEJ,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA;AAAA,MACC,KAAM,EAAA,4BAAA;AAAA,MACN,OAAQ,EAAA,YAAA;AAAA,MACR,YAAW,EAAA,sBAAA;AAAA,MAEX,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA;AAAA,QACC,QAAS,EAAA,SAAA;AAAA,QACT,QAAS,EAAA,SAAA;AAAA,QACT,CAAE,EAAA,y3BAAA;AAAA,QACF,IAAK,EAAA,cAAA;AAAA,OACP,CAAA;AAAA,KACF,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ;;;;"}
@@ -4,7 +4,7 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var react = require('@liveblocks/react');
6
6
  var react$1 = require('react');
7
- var classNames = require('../../utils/class-names.cjs');
7
+ var cn = require('../../utils/cn.cjs');
8
8
  var getInitials = require('../../utils/get-initials.cjs');
9
9
 
10
10
 
@@ -21,7 +21,7 @@ function Avatar({ userId, className, ...props }) {
21
21
  [isLoading, user, userId]
22
22
  );
23
23
  return /* @__PURE__ */ jsxRuntime.jsxs("div", {
24
- className: classNames.classNames("lb-avatar", className),
24
+ className: cn.cn("lb-avatar", className),
25
25
  "data-loading": isLoading ? "" : void 0,
26
26
  ...props,
27
27
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.cjs","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AAC6C;AACb;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
1
+ {"version":3,"file":"Avatar.cjs","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={cn(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AACqC;AACL;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
@@ -2,7 +2,7 @@
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { useUser } from '@liveblocks/react';
4
4
  import { useMemo } from 'react';
5
- import { classNames } from '../../utils/class-names.js';
5
+ import { cn } from '../../utils/cn.js';
6
6
  import { getInitials } from '../../utils/get-initials.js';
7
7
 
8
8
 
@@ -19,7 +19,7 @@ function Avatar({ userId, className, ...props }) {
19
19
  [isLoading, user, userId]
20
20
  );
21
21
  return /* @__PURE__ */ jsxs("div", {
22
- className: classNames("lb-avatar", className),
22
+ className: cn("lb-avatar", className),
23
23
  "data-loading": isLoading ? "" : void 0,
24
24
  ...props,
25
25
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.js","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AAC6C;AACb;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
1
+ {"version":3,"file":"Avatar.js","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={cn(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AACqC;AACL;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
@@ -4,7 +4,7 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var react = require('react');
6
6
  var ChevronDown = require('../../icons/ChevronDown.cjs');
7
- var classNames = require('../../utils/class-names.cjs');
7
+ var cn = require('../../utils/cn.cjs');
8
8
 
9
9
 
10
10
  const CustomButton = react.forwardRef(
@@ -18,7 +18,7 @@ const CustomButton = react.forwardRef(
18
18
  }, forwardedRef) => {
19
19
  return /* @__PURE__ */ jsxRuntime.jsx("button", {
20
20
  type: "button",
21
- className: classNames.classNames(
21
+ className: cn.cn(
22
22
  "lb-button",
23
23
  !disableable && "lb-button:non-disableable",
24
24
  className
@@ -54,7 +54,7 @@ const SelectButton = react.forwardRef(
54
54
  return /* @__PURE__ */ jsxRuntime.jsxs(CustomButton, {
55
55
  ...props,
56
56
  type: "button",
57
- className: classNames.classNames("lb-select-button", className),
57
+ className: cn.cn("lb-select-button", className),
58
58
  ref: forwardedRef,
59
59
  children: [
60
60
  icon ? /* @__PURE__ */ jsxRuntime.jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"Button.cjs","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { ChevronDownIcon } from \"../../icons/ChevronDown\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?:\n | \"default\"\n | \"toolbar\"\n | \"outline\"\n | \"primary\"\n | \"secondary\"\n | \"destructive\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n icon?: ReactNode;\n}\n\nexport const CustomButton = forwardRef<\n HTMLButtonElement,\n Omit<ButtonProps, \"icon\">\n>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n children,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </button>\n );\n }\n);\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, ...props }, forwardedRef) => {\n return (\n <CustomButton {...props} ref={forwardedRef}>\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n </CustomButton>\n );\n }\n);\n\nexport const SelectButton = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, className, ...props }, forwardedRef) => {\n return (\n <CustomButton\n {...props}\n type=\"button\"\n className={classNames(\"lb-select-button\", className)}\n ref={forwardedRef}\n >\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n <span className=\"lb-select-button-chevron\">\n <ChevronDownIcon />\n </span>\n </CustomButton>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;AAqBO;AAAqB;AAKxB;AACY;AACH;AACO;AACd;AACA;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AAEJ;AACH;AAGN;AAEO;AAAe;AAElB;AACG;AAAiB;AAAY;AAC3B;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AAAA;AACpE;AAGN;AAEO;AAAqB;AAExB;AACG;AACK;AACC;AAC8C;AAC9C;AAEJ;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AACjE;AAAe;AACG;AACnB;AAAA;AACF;AAGN;;;;"}
1
+ {"version":3,"file":"Button.cjs","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { ChevronDownIcon } from \"../../icons/ChevronDown\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?:\n | \"default\"\n | \"toolbar\"\n | \"outline\"\n | \"primary\"\n | \"secondary\"\n | \"destructive\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n icon?: ReactNode;\n}\n\nexport const CustomButton = forwardRef<\n HTMLButtonElement,\n Omit<ButtonProps, \"icon\">\n>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n children,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={cn(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </button>\n );\n }\n);\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, ...props }, forwardedRef) => {\n return (\n <CustomButton {...props} ref={forwardedRef}>\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n </CustomButton>\n );\n }\n);\n\nexport const SelectButton = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, className, ...props }, forwardedRef) => {\n return (\n <CustomButton\n {...props}\n type=\"button\"\n className={cn(\"lb-select-button\", className)}\n ref={forwardedRef}\n >\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n <span className=\"lb-select-button-chevron\">\n <ChevronDownIcon />\n </span>\n </CustomButton>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;AAqBO;AAAqB;AAKxB;AACY;AACH;AACO;AACd;AACA;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AAEJ;AACH;AAGN;AAEO;AAAe;AAElB;AACG;AAAiB;AAAY;AAC3B;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AAAA;AACpE;AAGN;AAEO;AAAqB;AAExB;AACG;AACK;AACC;AACsC;AACtC;AAEJ;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AACjE;AAAe;AACG;AACnB;AAAA;AACF;AAGN;;;;"}
@@ -2,7 +2,7 @@
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { forwardRef } from 'react';
4
4
  import { ChevronDownIcon } from '../../icons/ChevronDown.js';
5
- import { classNames } from '../../utils/class-names.js';
5
+ import { cn } from '../../utils/cn.js';
6
6
 
7
7
 
8
8
  const CustomButton = forwardRef(
@@ -16,7 +16,7 @@ const CustomButton = forwardRef(
16
16
  }, forwardedRef) => {
17
17
  return /* @__PURE__ */ jsx("button", {
18
18
  type: "button",
19
- className: classNames(
19
+ className: cn(
20
20
  "lb-button",
21
21
  !disableable && "lb-button:non-disableable",
22
22
  className
@@ -52,7 +52,7 @@ const SelectButton = forwardRef(
52
52
  return /* @__PURE__ */ jsxs(CustomButton, {
53
53
  ...props,
54
54
  type: "button",
55
- className: classNames("lb-select-button", className),
55
+ className: cn("lb-select-button", className),
56
56
  ref: forwardedRef,
57
57
  children: [
58
58
  icon ? /* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"Button.js","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { ChevronDownIcon } from \"../../icons/ChevronDown\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?:\n | \"default\"\n | \"toolbar\"\n | \"outline\"\n | \"primary\"\n | \"secondary\"\n | \"destructive\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n icon?: ReactNode;\n}\n\nexport const CustomButton = forwardRef<\n HTMLButtonElement,\n Omit<ButtonProps, \"icon\">\n>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n children,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </button>\n );\n }\n);\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, ...props }, forwardedRef) => {\n return (\n <CustomButton {...props} ref={forwardedRef}>\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n </CustomButton>\n );\n }\n);\n\nexport const SelectButton = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, className, ...props }, forwardedRef) => {\n return (\n <CustomButton\n {...props}\n type=\"button\"\n className={classNames(\"lb-select-button\", className)}\n ref={forwardedRef}\n >\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n <span className=\"lb-select-button-chevron\">\n <ChevronDownIcon />\n </span>\n </CustomButton>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;AAqBO;AAAqB;AAKxB;AACY;AACH;AACO;AACd;AACA;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AAEJ;AACH;AAGN;AAEO;AAAe;AAElB;AACG;AAAiB;AAAY;AAC3B;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AAAA;AACpE;AAGN;AAEO;AAAqB;AAExB;AACG;AACK;AACC;AAC8C;AAC9C;AAEJ;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AACjE;AAAe;AACG;AACnB;AAAA;AACF;AAGN;;"}
1
+ {"version":3,"file":"Button.js","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { ChevronDownIcon } from \"../../icons/ChevronDown\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?:\n | \"default\"\n | \"toolbar\"\n | \"outline\"\n | \"primary\"\n | \"secondary\"\n | \"destructive\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n icon?: ReactNode;\n}\n\nexport const CustomButton = forwardRef<\n HTMLButtonElement,\n Omit<ButtonProps, \"icon\">\n>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n children,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={cn(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </button>\n );\n }\n);\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, ...props }, forwardedRef) => {\n return (\n <CustomButton {...props} ref={forwardedRef}>\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n </CustomButton>\n );\n }\n);\n\nexport const SelectButton = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ icon, children, className, ...props }, forwardedRef) => {\n return (\n <CustomButton\n {...props}\n type=\"button\"\n className={cn(\"lb-select-button\", className)}\n ref={forwardedRef}\n >\n {icon ? <span className=\"lb-icon-container\">{icon}</span> : null}\n {children ? <span className=\"lb-button-label\">{children}</span> : null}\n <span className=\"lb-select-button-chevron\">\n <ChevronDownIcon />\n </span>\n </CustomButton>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;AAqBO;AAAqB;AAKxB;AACY;AACH;AACO;AACd;AACA;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AAEJ;AACH;AAGN;AAEO;AAAe;AAElB;AACG;AAAiB;AAAY;AAC3B;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AAAA;AACpE;AAGN;AAEO;AAAqB;AAExB;AACG;AACK;AACC;AACsC;AACtC;AAEJ;AAAQ;AAAe;AAAqB;AAAe;AAC/C;AAAe;AAAmB;AAAmB;AACjE;AAAe;AACG;AACnB;AAAA;AACF;AAGN;;"}
@@ -7,7 +7,7 @@ var react = require('react');
7
7
  var config = require('../../config.cjs');
8
8
  var constants = require('../../constants.cjs');
9
9
  var overrides = require('../../overrides.cjs');
10
- var classNames = require('../../utils/class-names.cjs');
10
+ var cn = require('../../utils/cn.cjs');
11
11
 
12
12
  function _interopNamespaceDefault(e) {
13
13
  var n = Object.create(null);
@@ -50,7 +50,7 @@ function Dropdown({
50
50
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Portal, {
51
51
  container: portalContainer,
52
52
  children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Content, {
53
- className: classNames.classNames(
53
+ className: cn.cn(
54
54
  "lb-root lb-portal lb-elevation lb-dropdown",
55
55
  className
56
56
  ),
@@ -66,7 +66,7 @@ function Dropdown({
66
66
  const DropdownItem = react.forwardRef(
67
67
  ({ children, className, icon, ...props }, forwardedRef) => {
68
68
  return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuPrimitive__namespace.DropdownMenuItem, {
69
- className: classNames.classNames("lb-dropdown-item", className),
69
+ className: cn.cn("lb-dropdown-item", className),
70
70
  ...props,
71
71
  ref: forwardedRef,
72
72
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.cjs","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\ninterface DropdownItemProps\n extends DropdownMenuPrimitive.DropdownMenuItemProps {\n icon?: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUiConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, className, icon, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {icon ? (\n <span className=\"lb-dropdown-item-icon lb-icon-container\">\n {icon}\n </span>\n ) : null}\n {children ? (\n <span className=\"lb-dropdown-item-label\">{children}</span>\n ) : null}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n }\n);\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEO;AAAqB;AAExB;AACG;AACoD;AAC/C;AACC;AAEJ;AACE;AAAe;AACb;AAED;AAED;AAAe;AAA0B;AACxC;AAAA;AACN;AAGN;;;;;;;"}
1
+ {"version":3,"file":"Dropdown.cjs","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\ninterface DropdownItemProps\n extends DropdownMenuPrimitive.DropdownMenuItemProps {\n icon?: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUiConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={cn(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, className, icon, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={cn(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {icon ? (\n <span className=\"lb-dropdown-item-icon lb-icon-container\">\n {icon}\n </span>\n ) : null}\n {children ? (\n <span className=\"lb-dropdown-item-label\">{children}</span>\n ) : null}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n }\n);\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEO;AAAqB;AAExB;AACG;AAC4C;AACvC;AACC;AAEJ;AACE;AAAe;AACb;AAED;AAED;AAAe;AAA0B;AACxC;AAAA;AACN;AAGN;;;;;;;"}
@@ -6,7 +6,7 @@ import { forwardRef } from 'react';
6
6
  import { useLiveblocksUiConfig } from '../../config.js';
7
7
  import { FLOATING_ELEMENT_SIDE_OFFSET, FLOATING_ELEMENT_COLLISION_PADDING } from '../../constants.js';
8
8
  import { useOverrides } from '../../overrides.js';
9
- import { classNames } from '../../utils/class-names.js';
9
+ import { cn } from '../../utils/cn.js';
10
10
 
11
11
 
12
12
  function Dropdown({
@@ -30,7 +30,7 @@ function Dropdown({
30
30
  /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, {
31
31
  container: portalContainer,
32
32
  children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.Content, {
33
- className: classNames(
33
+ className: cn(
34
34
  "lb-root lb-portal lb-elevation lb-dropdown",
35
35
  className
36
36
  ),
@@ -46,7 +46,7 @@ function Dropdown({
46
46
  const DropdownItem = forwardRef(
47
47
  ({ children, className, icon, ...props }, forwardedRef) => {
48
48
  return /* @__PURE__ */ jsxs(DropdownMenuPrimitive.DropdownMenuItem, {
49
- className: classNames("lb-dropdown-item", className),
49
+ className: cn("lb-dropdown-item", className),
50
50
  ...props,
51
51
  ref: forwardedRef,
52
52
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.js","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\ninterface DropdownItemProps\n extends DropdownMenuPrimitive.DropdownMenuItemProps {\n icon?: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUiConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, className, icon, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {icon ? (\n <span className=\"lb-dropdown-item-icon lb-icon-container\">\n {icon}\n </span>\n ) : null}\n {children ? (\n <span className=\"lb-dropdown-item-label\">{children}</span>\n ) : null}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n }\n);\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;;AA6BO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEO;AAAqB;AAExB;AACG;AACoD;AAC/C;AACC;AAEJ;AACE;AAAe;AACb;AAED;AAED;AAAe;AAA0B;AACxC;AAAA;AACN;AAGN;;"}
1
+ {"version":3,"file":"Dropdown.js","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\ninterface DropdownItemProps\n extends DropdownMenuPrimitive.DropdownMenuItemProps {\n icon?: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUiConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={cn(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n ({ children, className, icon, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={cn(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {icon ? (\n <span className=\"lb-dropdown-item-icon lb-icon-container\">\n {icon}\n </span>\n ) : null}\n {children ? (\n <span className=\"lb-dropdown-item-label\">{children}</span>\n ) : null}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n }\n);\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;;AA6BO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEO;AAAqB;AAExB;AACG;AAC4C;AACvC;AACC;AAEJ;AACE;AAAe;AACb;AAED;AAED;AAAe;AAA0B;AACxC;AAAA;AACN;AAGN;;"}