stream-chat-react 12.10.0 → 12.11.0

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 (187) hide show
  1. package/dist/components/Attachment/Attachment.js +2 -1
  2. package/dist/components/Attachment/AttachmentContainer.d.ts +1 -1
  3. package/dist/components/Attachment/AttachmentContainer.js +2 -2
  4. package/dist/components/Attachment/Card.js +3 -3
  5. package/dist/components/Attachment/VoiceRecording.d.ts +1 -1
  6. package/dist/components/Attachment/VoiceRecording.js +2 -2
  7. package/dist/components/Attachment/attachment-sizing.js +2 -1
  8. package/dist/components/Attachment/components/FileSizeIndicator.d.ts +1 -1
  9. package/dist/components/Attachment/components/FileSizeIndicator.js +1 -1
  10. package/dist/components/Attachment/hooks/useAudioController.js +3 -1
  11. package/dist/components/Attachment/utils.d.ts +1 -1
  12. package/dist/components/Attachment/utils.js +12 -3
  13. package/dist/components/AutoCompleteTextarea/List.js +3 -2
  14. package/dist/components/AutoCompleteTextarea/Textarea.js +3 -3
  15. package/dist/components/AutoCompleteTextarea/utils.js +2 -2
  16. package/dist/components/Avatar/ChannelAvatar.js +1 -1
  17. package/dist/components/Channel/Channel.d.ts +1 -1
  18. package/dist/components/Channel/Channel.js +27 -12
  19. package/dist/components/Channel/channelState.js +9 -3
  20. package/dist/components/Channel/hooks/useCreateChannelStateContext.js +5 -3
  21. package/dist/components/Channel/hooks/useMentionsHandlers.js +5 -2
  22. package/dist/components/Channel/utils.js +2 -1
  23. package/dist/components/ChannelHeader/ChannelHeader.js +1 -1
  24. package/dist/components/ChannelList/ChannelList.js +13 -8
  25. package/dist/components/ChannelList/hooks/useChannelListShape.d.ts +2 -2
  26. package/dist/components/ChannelList/hooks/useChannelListShape.js +44 -17
  27. package/dist/components/ChannelList/hooks/useChannelUpdatedListener.js +2 -1
  28. package/dist/components/ChannelList/hooks/useMessageNewListener.js +3 -1
  29. package/dist/components/ChannelList/hooks/usePaginatedChannels.js +4 -2
  30. package/dist/components/ChannelList/hooks/useSelectedChannelState.js +1 -1
  31. package/dist/components/ChannelPreview/ChannelPreview.js +2 -2
  32. package/dist/components/ChannelPreview/ChannelPreviewMessenger.js +1 -1
  33. package/dist/components/ChannelPreview/icons.js +0 -1
  34. package/dist/components/ChannelPreview/utils.js +3 -3
  35. package/dist/components/ChannelSearch/ChannelSearch.js +5 -3
  36. package/dist/components/ChannelSearch/SearchResults.js +1 -1
  37. package/dist/components/ChannelSearch/hooks/useChannelSearch.d.ts +4 -2
  38. package/dist/components/ChannelSearch/hooks/useChannelSearch.js +61 -36
  39. package/dist/components/ChannelSearch/index.d.ts +1 -1
  40. package/dist/components/Chat/hooks/useChat.js +4 -2
  41. package/dist/components/Chat/hooks/useCreateChatClient.js +3 -1
  42. package/dist/components/ChatAutoComplete/ChatAutoComplete.js +1 -1
  43. package/dist/components/ChatView/ChatView.js +0 -1
  44. package/dist/components/Dialog/PromptDialog.d.ts +1 -1
  45. package/dist/components/Dialog/PromptDialog.js +1 -1
  46. package/dist/components/EventComponent/EventComponent.js +1 -1
  47. package/dist/components/Gallery/Image.js +1 -1
  48. package/dist/components/Gallery/ModalGallery.js +1 -2
  49. package/dist/components/InfiniteScrollPaginator/InfiniteScroll.js +5 -2
  50. package/dist/components/InfiniteScrollPaginator/InfiniteScrollPaginator.js +1 -1
  51. package/dist/components/LoadMore/LoadMorePaginator.js +1 -1
  52. package/dist/components/MML/MML.js +1 -0
  53. package/dist/components/MediaRecorder/transcode/wav.js +6 -3
  54. package/dist/components/Message/FixedHeightMessage.js +6 -8
  55. package/dist/components/Message/Message.js +2 -1
  56. package/dist/components/Message/MessageEditedTimestamp.js +1 -1
  57. package/dist/components/Message/MessageSimple.js +2 -5
  58. package/dist/components/Message/MessageStatus.js +1 -1
  59. package/dist/components/Message/MessageText.js +7 -7
  60. package/dist/components/Message/QuotedMessage.js +2 -2
  61. package/dist/components/Message/Timestamp.js +9 -1
  62. package/dist/components/Message/hooks/useActionHandler.js +1 -1
  63. package/dist/components/Message/hooks/useFlagHandler.js +2 -1
  64. package/dist/components/Message/hooks/useMarkUnreadHandler.js +2 -1
  65. package/dist/components/Message/hooks/useMessageTextStreaming.d.ts +1 -1
  66. package/dist/components/Message/hooks/useMessageTextStreaming.js +1 -1
  67. package/dist/components/Message/hooks/useMuteHandler.js +7 -4
  68. package/dist/components/Message/hooks/usePinHandler.js +1 -1
  69. package/dist/components/Message/hooks/useReactionHandler.js +10 -5
  70. package/dist/components/Message/hooks/useRetryHandler.js +1 -1
  71. package/dist/components/Message/hooks/useUserRole.js +1 -1
  72. package/dist/components/Message/renderText/renderText.js +2 -2
  73. package/dist/components/Message/utils.js +3 -3
  74. package/dist/components/MessageActions/MessageActionsBox.js +7 -3
  75. package/dist/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.js +1 -1
  76. package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.js +4 -2
  77. package/dist/components/MessageInput/AttachmentPreviewList/UnsupportedAttachmentPreview.js +4 -2
  78. package/dist/components/MessageInput/AttachmentSelector.js +1 -1
  79. package/dist/components/MessageInput/DefaultTriggerProvider.js +1 -1
  80. package/dist/components/MessageInput/DropzoneProvider.js +1 -1
  81. package/dist/components/MessageInput/MessageInput.js +1 -1
  82. package/dist/components/MessageInput/MessageInputFlat.js +4 -3
  83. package/dist/components/MessageInput/QuotedMessagePreview.js +1 -1
  84. package/dist/components/MessageInput/hooks/useAttachments.js +12 -4
  85. package/dist/components/MessageInput/hooks/useLinkPreviews.js +3 -1
  86. package/dist/components/MessageInput/hooks/useMessageInputState.js +4 -3
  87. package/dist/components/MessageInput/hooks/useMessageInputText.js +3 -1
  88. package/dist/components/MessageInput/hooks/useSubmitHandler.js +5 -3
  89. package/dist/components/MessageInput/hooks/useUserTrigger.js +2 -2
  90. package/dist/components/MessageInput/hooks/utils.js +6 -2
  91. package/dist/components/MessageList/ConnectionStatus.js +1 -1
  92. package/dist/components/MessageList/MessageList.js +5 -5
  93. package/dist/components/MessageList/MessageListNotifications.js +3 -1
  94. package/dist/components/MessageList/VirtualizedMessageList.js +17 -10
  95. package/dist/components/MessageList/VirtualizedMessageListComponents.js +2 -2
  96. package/dist/components/MessageList/hooks/MessageList/useMessageListElements.js +1 -3
  97. package/dist/components/MessageList/hooks/MessageList/useMessageListScrollManager.js +2 -1
  98. package/dist/components/MessageList/hooks/MessageList/useScrollLocationLogic.js +3 -2
  99. package/dist/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.js +6 -2
  100. package/dist/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.js +2 -1
  101. package/dist/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.js +7 -3
  102. package/dist/components/MessageList/utils.js +28 -11
  103. package/dist/components/Modal/Modal.d.ts +1 -1
  104. package/dist/components/Modal/Modal.js +1 -1
  105. package/dist/components/Modal/ModalHeader.js +1 -1
  106. package/dist/components/Poll/Poll.js +1 -1
  107. package/dist/components/Poll/PollActions/PollActions.js +6 -4
  108. package/dist/components/Poll/PollActions/PollAnswerList.js +1 -1
  109. package/dist/components/Poll/PollActions/PollResults/PollOptionVotesList.js +1 -1
  110. package/dist/components/Poll/PollActions/PollResults/PollOptionWithLatestVotes.js +4 -2
  111. package/dist/components/Poll/PollActions/PollResults/PollResults.js +2 -1
  112. package/dist/components/Poll/PollContent.js +1 -1
  113. package/dist/components/Poll/PollCreationDialog/OptionFieldSet.d.ts +1 -1
  114. package/dist/components/Poll/PollCreationDialog/OptionFieldSet.js +11 -4
  115. package/dist/components/Poll/PollCreationDialog/PollCreationDialog.js +13 -4
  116. package/dist/components/Poll/PollCreationDialog/PollCreationDialogControls.js +6 -3
  117. package/dist/components/Poll/PollOptionList.js +1 -1
  118. package/dist/components/Poll/PollOptionSelector.js +12 -5
  119. package/dist/components/Poll/hooks/useManagePollVotesRealtime.js +9 -4
  120. package/dist/components/Poll/hooks/usePollAnswerPagination.js +8 -2
  121. package/dist/components/Poll/hooks/usePollOptionVotesPagination.js +8 -2
  122. package/dist/components/ReactFileUtilities/FileIcon/mimeTypes.d.ts +1 -1
  123. package/dist/components/ReactFileUtilities/ImageDropzone.js +3 -1
  124. package/dist/components/ReactFileUtilities/UploadButton.js +1 -1
  125. package/dist/components/ReactFileUtilities/utils.js +3 -1
  126. package/dist/components/Reactions/ReactionSelector.js +3 -1
  127. package/dist/components/Reactions/ReactionSelectorWithButton.js +1 -1
  128. package/dist/components/Reactions/ReactionsList.d.ts +2 -2
  129. package/dist/components/Reactions/ReactionsList.js +7 -4
  130. package/dist/components/Reactions/ReactionsListModal.d.ts +1 -2
  131. package/dist/components/Reactions/ReactionsListModal.js +1 -1
  132. package/dist/components/Reactions/SpriteImage.js +6 -2
  133. package/dist/components/Reactions/hooks/useFetchReactions.js +1 -1
  134. package/dist/components/Reactions/hooks/useProcessReactions.js +1 -1
  135. package/dist/components/Reactions/index.d.ts +1 -0
  136. package/dist/components/Reactions/index.js +1 -0
  137. package/dist/components/Reactions/reactionOptions.js +20 -5
  138. package/dist/components/Thread/Thread.js +4 -3
  139. package/dist/components/Threads/ThreadContext.d.ts +1 -1
  140. package/dist/components/Threads/ThreadContext.js +1 -1
  141. package/dist/components/Threads/ThreadList/ThreadList.js +1 -1
  142. package/dist/components/Threads/ThreadList/ThreadListItem.d.ts +1 -1
  143. package/dist/components/Threads/ThreadList/ThreadListItem.js +1 -1
  144. package/dist/components/Threads/ThreadList/ThreadListItemUI.js +5 -3
  145. package/dist/components/Threads/icons.js +0 -1
  146. package/dist/components/Tooltip/Tooltip.d.ts +1 -1
  147. package/dist/components/Tooltip/Tooltip.js +1 -1
  148. package/dist/context/ComponentContext.d.ts +3 -1
  149. package/dist/context/ComponentContext.js +1 -1
  150. package/dist/context/DialogManagerContext.d.ts +1 -1
  151. package/dist/context/DialogManagerContext.js +1 -1
  152. package/dist/context/MessageBounceContext.js +2 -2
  153. package/dist/context/MessageContext.js +1 -1
  154. package/dist/context/WithComponents.js +1 -1
  155. package/dist/css/v2/index.css +2 -2
  156. package/dist/css/v2/index.layout.css +2 -2
  157. package/dist/experimental/MessageActions/MessageActions.js +0 -1
  158. package/dist/experimental/MessageActions/defaults.js +31 -7
  159. package/dist/experimental/index.browser.cjs +103 -37
  160. package/dist/experimental/index.browser.cjs.map +2 -2
  161. package/dist/experimental/index.node.cjs +103 -37
  162. package/dist/experimental/index.node.cjs.map +2 -2
  163. package/dist/i18n/Streami18n.js +11 -2
  164. package/dist/i18n/utils.js +14 -1
  165. package/dist/index.browser.cjs +1771 -981
  166. package/dist/index.browser.cjs.map +4 -4
  167. package/dist/index.node.cjs +1772 -981
  168. package/dist/index.node.cjs.map +4 -4
  169. package/dist/plugins/Emojis/EmojiPicker.js +0 -1
  170. package/dist/plugins/Emojis/index.browser.cjs +3 -1
  171. package/dist/plugins/Emojis/index.browser.cjs.map +2 -2
  172. package/dist/plugins/Emojis/index.node.cjs +3 -1
  173. package/dist/plugins/Emojis/index.node.cjs.map +2 -2
  174. package/dist/plugins/encoders/mp3.browser.cjs +7 -4
  175. package/dist/plugins/encoders/mp3.browser.cjs.map +2 -2
  176. package/dist/plugins/encoders/mp3.node.cjs +7 -4
  177. package/dist/plugins/encoders/mp3.node.cjs.map +2 -2
  178. package/dist/scss/v2/ChannelSearch/ChannelSearch-layout.scss +1 -0
  179. package/dist/scss/v2/Message/Message-layout.scss +12 -5
  180. package/dist/scss/v2/Poll/Poll-layout.scss +1 -1
  181. package/dist/scss/v2/Search/Search-layout.scss +148 -0
  182. package/dist/scss/v2/Search/Search-theme.scss +222 -0
  183. package/dist/scss/v2/_icons.scss +2 -0
  184. package/dist/scss/v2/index.layout.scss +1 -0
  185. package/dist/scss/v2/index.scss +1 -0
  186. package/dist/store/hooks/useStateStore.js +35 -11
  187. package/package.json +21 -33
@@ -1,4 +1,3 @@
1
- /* eslint-disable typescript-sort-keys/interface */
2
1
  import React, { useEffect, useState } from 'react';
3
2
  import { usePopper } from 'react-popper';
4
3
  import Picker from '@emoji-mart/react';
@@ -108,7 +108,9 @@ var EmojiPicker = (props) => {
108
108
  const { t } = useTranslationContext("EmojiPicker");
109
109
  const { insertText, textareaRef } = useMessageInputContext("EmojiPicker");
110
110
  const [displayPicker, setDisplayPicker] = (0, import_react4.useState)(false);
111
- const [referenceElement, setReferenceElement] = (0, import_react4.useState)(null);
111
+ const [referenceElement, setReferenceElement] = (0, import_react4.useState)(
112
+ null
113
+ );
112
114
  const [popperElement, setPopperElement] = (0, import_react4.useState)(null);
113
115
  const { attributes, styles } = (0, import_react_popper.usePopper)(referenceElement, popperElement, {
114
116
  placement: "top-end",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/plugins/Emojis/index.ts", "../../../src/plugins/Emojis/EmojiPicker.tsx", "../../../src/context/TranslationContext.tsx", "../../../src/i18n/utils.ts", "../../../src/context/MessageInputContext.tsx", "../../../src/plugins/Emojis/icons.tsx"],
4
- "sourcesContent": ["export * from './EmojiPicker';\nexport { EmojiPickerIcon } from './icons';\n", "/* eslint-disable typescript-sort-keys/interface */\nimport React, { useEffect, useState } from 'react';\nimport { usePopper } from 'react-popper';\nimport Picker from '@emoji-mart/react';\n\nimport type { Options } from '@popperjs/core';\n\nimport { useMessageInputContext, useTranslationContext } from '../../context';\nimport { EmojiPickerIcon } from './icons';\n\nconst isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;\n\nexport type EmojiPickerProps = {\n ButtonIconComponent?: React.ComponentType;\n buttonClassName?: string;\n pickerContainerClassName?: string;\n wrapperClassName?: string;\n closeOnEmojiSelect?: boolean;\n /**\n * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.5.2#options--props) to be\n * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.5.2#-picker) component\n */\n pickerProps?: Partial<{ theme: 'auto' | 'light' | 'dark' } & Record<string, unknown>>;\n /**\n * [React Popper options](https://popper.js.org/docs/v2/constructors/#options) to be\n * passed down to the [react-popper `usePopper`](https://popper.js.org/react-popper/v2/hook/) hook\n */\n popperOptions?: Partial<Options>;\n};\n\nconst classNames: EmojiPickerProps = {\n buttonClassName: 'str-chat__emoji-picker-button',\n pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',\n wrapperClassName: 'str-chat__message-textarea-emoji-picker',\n};\n\nexport const EmojiPicker = (props: EmojiPickerProps) => {\n const { t } = useTranslationContext('EmojiPicker');\n const { insertText, textareaRef } = useMessageInputContext('EmojiPicker');\n const [displayPicker, setDisplayPicker] = useState(false);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);\n const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);\n const { attributes, styles } = usePopper(referenceElement, popperElement, {\n placement: 'top-end',\n ...props.popperOptions,\n });\n\n const { buttonClassName, pickerContainerClassName, wrapperClassName } = classNames;\n\n const { ButtonIconComponent = EmojiPickerIcon } = props;\n\n useEffect(() => {\n if (!popperElement || !referenceElement) return;\n\n const handlePointerDown = (e: PointerEvent) => {\n const target = e.target as HTMLElement;\n\n const rootNode = target.getRootNode();\n\n if (\n popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||\n referenceElement.contains(target)\n ) {\n return;\n }\n\n setDisplayPicker(false);\n };\n\n window.addEventListener('pointerdown', handlePointerDown);\n return () => window.removeEventListener('pointerdown', handlePointerDown);\n }, [referenceElement, popperElement]);\n\n return (\n <div className={props.wrapperClassName ?? wrapperClassName}>\n {displayPicker && (\n <div\n className={props.pickerContainerClassName ?? pickerContainerClassName}\n style={styles.popper}\n {...attributes.popper}\n ref={setPopperElement}\n >\n <Picker\n data={async () => (await import('@emoji-mart/data')).default}\n onEmojiSelect={(e: { native: string }) => {\n insertText(e.native);\n textareaRef.current?.focus();\n if (props.closeOnEmojiSelect) {\n setDisplayPicker(false);\n }\n }}\n {...props.pickerProps}\n />\n </div>\n )}\n <button\n aria-expanded={displayPicker}\n aria-label={t('aria/Emoji picker')}\n className={props.buttonClassName ?? buttonClassName}\n onClick={() => setDisplayPicker((cv) => !cv)}\n ref={setReferenceElement}\n type='button'\n >\n {ButtonIconComponent && <ButtonIconComponent />}\n </button>\n </div>\n );\n};\n", "import React, { PropsWithChildren, useContext } from 'react';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar';\nimport localizedFormat from 'dayjs/plugin/localizedFormat';\n\nimport { getDisplayName } from './utils/getDisplayName';\nimport { defaultDateTimeParser, defaultTranslatorFunction } from '../i18n/utils';\n\nimport type { TFunction } from 'i18next';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { UnknownType } from '../types/types';\nimport type { TDateTimeParser } from '../i18n/types';\n\nDayjs.extend(calendar);\nDayjs.extend(localizedFormat);\n\nexport type TranslationContextValue = {\n t: TFunction;\n tDateTimeParser: TDateTimeParser;\n userLanguage: TranslationLanguages;\n};\n\nexport const TranslationContext = React.createContext<TranslationContextValue>({\n t: defaultTranslatorFunction,\n tDateTimeParser: defaultDateTimeParser,\n userLanguage: 'en',\n});\n\nexport const TranslationProvider = ({\n children,\n value,\n}: PropsWithChildren<{ value: TranslationContextValue }>) => (\n <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>\n);\n\nexport const useTranslationContext = (componentName?: string) => {\n const contextValue = useContext(TranslationContext);\n\n if (!contextValue) {\n console.warn(\n `The useTranslationContext hook was called outside of the TranslationContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as TranslationContextValue;\n }\n\n return contextValue;\n};\n\nexport const withTranslationContext = <P extends UnknownType>(\n Component: React.ComponentType<P>,\n) => {\n const WithTranslationContextComponent = (props: Omit<P, keyof TranslationContextValue>) => {\n const translationContext = useTranslationContext();\n\n return <Component {...(props as P)} {...translationContext} />;\n };\n\n WithTranslationContextComponent.displayName = `WithTranslationContext${getDisplayName(\n Component,\n )}`;\n\n return WithTranslationContextComponent;\n};\n", "import Dayjs from 'dayjs';\n\nimport type { TFunction } from 'i18next';\nimport type { Moment } from 'moment-timezone';\nimport type {\n DateFormatterOptions,\n PredefinedFormatters,\n SupportedTranslations,\n TDateTimeParserInput,\n TDateTimeParserOutput,\n TimestampFormatterOptions,\n} from './types';\n\nexport const notValidDateWarning =\n 'MessageTimestamp was called without a message, or message has invalid created_at date.';\nexport const noParsingFunctionWarning =\n 'MessageTimestamp was called but there is no datetime parsing function available';\n\nexport const isNumberOrString = (output: TDateTimeParserOutput): output is number | string =>\n typeof output === 'string' || typeof output === 'number';\n\nexport const isDayOrMoment = (output: TDateTimeParserOutput): output is Dayjs.Dayjs | Moment =>\n !!(output as Dayjs.Dayjs | Moment)?.isSame;\n\nexport const isDate = (output: TDateTimeParserOutput): output is Date =>\n !!(output as Date)?.getMonth;\n\nexport function getDateString({\n calendar,\n calendarFormats,\n format,\n formatDate,\n messageCreatedAt,\n t,\n tDateTimeParser,\n timestampTranslationKey,\n}: DateFormatterOptions): string | number | null {\n if (\n !messageCreatedAt ||\n (typeof messageCreatedAt === 'string' && !Date.parse(messageCreatedAt))\n ) {\n console.warn(notValidDateWarning);\n return null;\n }\n\n if (typeof formatDate === 'function') {\n return formatDate(new Date(messageCreatedAt));\n }\n\n if (t && timestampTranslationKey) {\n const options: TimestampFormatterOptions = {};\n if (typeof calendar !== 'undefined' && calendar !== null) options.calendar = calendar;\n if (typeof calendarFormats !== 'undefined' && calendarFormats !== null)\n options.calendarFormats = calendarFormats;\n if (typeof format !== 'undefined' && format !== null) options.format = format;\n\n const translatedTimestamp = t(timestampTranslationKey, {\n ...options,\n timestamp: new Date(messageCreatedAt),\n });\n const translationKeyFound = timestampTranslationKey !== translatedTimestamp;\n if (translationKeyFound) return translatedTimestamp;\n }\n\n if (!tDateTimeParser) {\n console.warn(noParsingFunctionWarning);\n return null;\n }\n\n const parsedTime = tDateTimeParser(messageCreatedAt);\n\n if (isDayOrMoment(parsedTime)) {\n /**\n * parsedTime.calendar is guaranteed on the type but is only\n * available when a user calls dayjs.extend(calendar)\n */\n return calendar && parsedTime.calendar\n ? parsedTime.calendar(undefined, calendarFormats || undefined)\n : parsedTime.format(format || undefined);\n }\n\n if (isDate(parsedTime)) {\n return parsedTime.toDateString();\n }\n\n if (isNumberOrString(parsedTime)) {\n return parsedTime;\n }\n\n return null;\n}\n\nexport const predefinedFormatters: PredefinedFormatters = {\n timestampFormatter: (streamI18n) => (\n value,\n _,\n {\n calendarFormats,\n ...options\n }: Pick<TimestampFormatterOptions, 'calendar' | 'format'> & {\n calendarFormats?: Record<string, string> | string;\n },\n ) => {\n let parsedCalendarFormats;\n try {\n if (!options.calendar) {\n parsedCalendarFormats = {};\n } else if (typeof calendarFormats === 'string') {\n parsedCalendarFormats = JSON.parse(calendarFormats);\n } else if (typeof calendarFormats === 'object') {\n parsedCalendarFormats = calendarFormats;\n }\n } catch (e) {\n console.error('[TIMESTAMP FORMATTER]', e);\n }\n\n const result = getDateString({\n ...options,\n calendarFormats: parsedCalendarFormats,\n messageCreatedAt: value,\n tDateTimeParser: streamI18n.tDateTimeParser,\n });\n if (!result || typeof result === 'number') {\n return JSON.stringify(value);\n }\n return result;\n },\n};\n\nexport const defaultTranslatorFunction: TFunction = <tResult = string>(key: tResult) => key;\n\nexport const defaultDateTimeParser = (input?: TDateTimeParserInput) => Dayjs(input);\n\nexport const isLanguageSupported = (language: string): language is SupportedTranslations => {\n const translations = ['de', 'en', 'es', 'fr', 'hi', 'it', 'ja', 'ko', 'nl', 'pt', 'ru', 'tr'];\n return translations.some((translation) => language === translation);\n};\n", "import React, { createContext, PropsWithChildren, useContext } from 'react';\n\nimport type { TriggerSettings } from '../components/MessageInput/DefaultTriggerProvider';\nimport type { CooldownTimerState, MessageInputProps } from '../components/MessageInput';\nimport type {\n CommandsListState,\n MentionsListState,\n MessageInputHookProps,\n MessageInputState,\n} from '../components/MessageInput/hooks/useMessageInputState';\n\nimport type { CustomTrigger, DefaultStreamChatGenerics } from '../types/types';\n\nexport type MessageInputContextValue<\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n> = MessageInputState<StreamChatGenerics> &\n MessageInputHookProps<StreamChatGenerics> &\n Omit<MessageInputProps<StreamChatGenerics, V>, 'Input'> &\n CooldownTimerState & {\n autocompleteTriggers?: TriggerSettings<StreamChatGenerics, V>;\n } & CommandsListState &\n MentionsListState;\n\nexport const MessageInputContext = createContext<\n (MessageInputState & MessageInputHookProps) | undefined\n>(undefined);\n\nexport const MessageInputContextProvider = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n>({\n children,\n value,\n}: PropsWithChildren<{\n value: MessageInputContextValue<StreamChatGenerics, V>;\n}>) => (\n <MessageInputContext.Provider value={value as MessageInputContextValue}>\n {children}\n </MessageInputContext.Provider>\n);\n\nexport const useMessageInputContext = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n>(\n componentName?: string,\n) => {\n const contextValue = useContext(MessageInputContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageInputContext hook was called outside of the MessageInputContext provider. Make sure this hook is called within the MessageInput's UI component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageInputContextValue<StreamChatGenerics, V>;\n }\n\n return contextValue as MessageInputContextValue<StreamChatGenerics, V>;\n};\n", "import React from 'react';\n\nexport const EmojiPickerIcon = () => (\n <svg\n preserveAspectRatio='xMinYMin'\n viewBox='0 0 28 28'\n width='100%'\n xmlns='http://www.w3.org/2000/svg'\n >\n <g clipRule='evenodd' fillRule='evenodd'>\n <path d='M14 4.4C8.6 4.4 4.4 8.6 4.4 14c0 5.4 4.2 9.6 9.6 9.6c5.4 0 9.6-4.2 9.6-9.6c0-5.4-4.2-9.6-9.6-9.6zM2 14c0-6.6 5.4-12 12-12s12 5.4 12 12s-5.4 12-12 12s-12-5.4-12-12zM12.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM18.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM8.6 15.4c.6-.4 1.2-.2 1.6.2c.6.8 1.6 1.8 3 2c1.2.4 2.8.2 4.8-2c.4-.4 1.2-.6 1.6 0c.4.4.6 1.2 0 1.6c-2.2 2.6-4.8 3.4-7 3c-2-.4-3.6-1.8-4.4-3c-.4-.6-.2-1.2.4-1.8z'></path>\n </g>\n </svg>\n);\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export * from './EmojiPicker';\nexport { EmojiPickerIcon } from './icons';\n", "import React, { useEffect, useState } from 'react';\nimport { usePopper } from 'react-popper';\nimport Picker from '@emoji-mart/react';\n\nimport type { Options } from '@popperjs/core';\n\nimport { useMessageInputContext, useTranslationContext } from '../../context';\nimport { EmojiPickerIcon } from './icons';\n\nconst isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;\n\nexport type EmojiPickerProps = {\n ButtonIconComponent?: React.ComponentType;\n buttonClassName?: string;\n pickerContainerClassName?: string;\n wrapperClassName?: string;\n closeOnEmojiSelect?: boolean;\n /**\n * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.5.2#options--props) to be\n * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.5.2#-picker) component\n */\n pickerProps?: Partial<{ theme: 'auto' | 'light' | 'dark' } & Record<string, unknown>>;\n /**\n * [React Popper options](https://popper.js.org/docs/v2/constructors/#options) to be\n * passed down to the [react-popper `usePopper`](https://popper.js.org/react-popper/v2/hook/) hook\n */\n popperOptions?: Partial<Options>;\n};\n\nconst classNames: EmojiPickerProps = {\n buttonClassName: 'str-chat__emoji-picker-button',\n pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',\n wrapperClassName: 'str-chat__message-textarea-emoji-picker',\n};\n\nexport const EmojiPicker = (props: EmojiPickerProps) => {\n const { t } = useTranslationContext('EmojiPicker');\n const { insertText, textareaRef } = useMessageInputContext('EmojiPicker');\n const [displayPicker, setDisplayPicker] = useState(false);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(\n null,\n );\n const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);\n const { attributes, styles } = usePopper(referenceElement, popperElement, {\n placement: 'top-end',\n ...props.popperOptions,\n });\n\n const { buttonClassName, pickerContainerClassName, wrapperClassName } = classNames;\n\n const { ButtonIconComponent = EmojiPickerIcon } = props;\n\n useEffect(() => {\n if (!popperElement || !referenceElement) return;\n\n const handlePointerDown = (e: PointerEvent) => {\n const target = e.target as HTMLElement;\n\n const rootNode = target.getRootNode();\n\n if (\n popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||\n referenceElement.contains(target)\n ) {\n return;\n }\n\n setDisplayPicker(false);\n };\n\n window.addEventListener('pointerdown', handlePointerDown);\n return () => window.removeEventListener('pointerdown', handlePointerDown);\n }, [referenceElement, popperElement]);\n\n return (\n <div className={props.wrapperClassName ?? wrapperClassName}>\n {displayPicker && (\n <div\n className={props.pickerContainerClassName ?? pickerContainerClassName}\n style={styles.popper}\n {...attributes.popper}\n ref={setPopperElement}\n >\n <Picker\n data={async () => (await import('@emoji-mart/data')).default}\n onEmojiSelect={(e: { native: string }) => {\n insertText(e.native);\n textareaRef.current?.focus();\n if (props.closeOnEmojiSelect) {\n setDisplayPicker(false);\n }\n }}\n {...props.pickerProps}\n />\n </div>\n )}\n <button\n aria-expanded={displayPicker}\n aria-label={t('aria/Emoji picker')}\n className={props.buttonClassName ?? buttonClassName}\n onClick={() => setDisplayPicker((cv) => !cv)}\n ref={setReferenceElement}\n type='button'\n >\n {ButtonIconComponent && <ButtonIconComponent />}\n </button>\n </div>\n );\n};\n", "import React, { PropsWithChildren, useContext } from 'react';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar';\nimport localizedFormat from 'dayjs/plugin/localizedFormat';\n\nimport { getDisplayName } from './utils/getDisplayName';\nimport { defaultDateTimeParser, defaultTranslatorFunction } from '../i18n/utils';\n\nimport type { TFunction } from 'i18next';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { UnknownType } from '../types/types';\nimport type { TDateTimeParser } from '../i18n/types';\n\nDayjs.extend(calendar);\nDayjs.extend(localizedFormat);\n\nexport type TranslationContextValue = {\n t: TFunction;\n tDateTimeParser: TDateTimeParser;\n userLanguage: TranslationLanguages;\n};\n\nexport const TranslationContext = React.createContext<TranslationContextValue>({\n t: defaultTranslatorFunction,\n tDateTimeParser: defaultDateTimeParser,\n userLanguage: 'en',\n});\n\nexport const TranslationProvider = ({\n children,\n value,\n}: PropsWithChildren<{ value: TranslationContextValue }>) => (\n <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>\n);\n\nexport const useTranslationContext = (componentName?: string) => {\n const contextValue = useContext(TranslationContext);\n\n if (!contextValue) {\n console.warn(\n `The useTranslationContext hook was called outside of the TranslationContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as TranslationContextValue;\n }\n\n return contextValue;\n};\n\nexport const withTranslationContext = <P extends UnknownType>(\n Component: React.ComponentType<P>,\n) => {\n const WithTranslationContextComponent = (\n props: Omit<P, keyof TranslationContextValue>,\n ) => {\n const translationContext = useTranslationContext();\n\n return <Component {...(props as P)} {...translationContext} />;\n };\n\n WithTranslationContextComponent.displayName = `WithTranslationContext${getDisplayName(\n Component,\n )}`;\n\n return WithTranslationContextComponent;\n};\n", "import Dayjs from 'dayjs';\n\nimport type { TFunction } from 'i18next';\nimport type { Moment } from 'moment-timezone';\nimport type {\n DateFormatterOptions,\n PredefinedFormatters,\n SupportedTranslations,\n TDateTimeParserInput,\n TDateTimeParserOutput,\n TimestampFormatterOptions,\n} from './types';\n\nexport const notValidDateWarning =\n 'MessageTimestamp was called without a message, or message has invalid created_at date.';\nexport const noParsingFunctionWarning =\n 'MessageTimestamp was called but there is no datetime parsing function available';\n\nexport const isNumberOrString = (\n output: TDateTimeParserOutput,\n): output is number | string => typeof output === 'string' || typeof output === 'number';\n\nexport const isDayOrMoment = (\n output: TDateTimeParserOutput,\n): output is Dayjs.Dayjs | Moment => !!(output as Dayjs.Dayjs | Moment)?.isSame;\n\nexport const isDate = (output: TDateTimeParserOutput): output is Date =>\n !!(output as Date)?.getMonth;\n\nexport function getDateString({\n calendar,\n calendarFormats,\n format,\n formatDate,\n messageCreatedAt,\n t,\n tDateTimeParser,\n timestampTranslationKey,\n}: DateFormatterOptions): string | number | null {\n if (\n !messageCreatedAt ||\n (typeof messageCreatedAt === 'string' && !Date.parse(messageCreatedAt))\n ) {\n console.warn(notValidDateWarning);\n return null;\n }\n\n if (typeof formatDate === 'function') {\n return formatDate(new Date(messageCreatedAt));\n }\n\n if (t && timestampTranslationKey) {\n const options: TimestampFormatterOptions = {};\n if (typeof calendar !== 'undefined' && calendar !== null) options.calendar = calendar;\n if (typeof calendarFormats !== 'undefined' && calendarFormats !== null)\n options.calendarFormats = calendarFormats;\n if (typeof format !== 'undefined' && format !== null) options.format = format;\n\n const translatedTimestamp = t(timestampTranslationKey, {\n ...options,\n timestamp: new Date(messageCreatedAt),\n });\n const translationKeyFound = timestampTranslationKey !== translatedTimestamp;\n if (translationKeyFound) return translatedTimestamp;\n }\n\n if (!tDateTimeParser) {\n console.warn(noParsingFunctionWarning);\n return null;\n }\n\n const parsedTime = tDateTimeParser(messageCreatedAt);\n\n if (isDayOrMoment(parsedTime)) {\n /**\n * parsedTime.calendar is guaranteed on the type but is only\n * available when a user calls dayjs.extend(calendar)\n */\n return calendar && parsedTime.calendar\n ? parsedTime.calendar(undefined, calendarFormats || undefined)\n : parsedTime.format(format || undefined);\n }\n\n if (isDate(parsedTime)) {\n return parsedTime.toDateString();\n }\n\n if (isNumberOrString(parsedTime)) {\n return parsedTime;\n }\n\n return null;\n}\n\nexport const predefinedFormatters: PredefinedFormatters = {\n timestampFormatter:\n (streamI18n) =>\n (\n value,\n _,\n {\n calendarFormats,\n ...options\n }: Pick<TimestampFormatterOptions, 'calendar' | 'format'> & {\n calendarFormats?: Record<string, string> | string;\n },\n ) => {\n let parsedCalendarFormats;\n try {\n if (!options.calendar) {\n parsedCalendarFormats = {};\n } else if (typeof calendarFormats === 'string') {\n parsedCalendarFormats = JSON.parse(calendarFormats);\n } else if (typeof calendarFormats === 'object') {\n parsedCalendarFormats = calendarFormats;\n }\n } catch (e) {\n console.error('[TIMESTAMP FORMATTER]', e);\n }\n\n const result = getDateString({\n ...options,\n calendarFormats: parsedCalendarFormats,\n messageCreatedAt: value,\n tDateTimeParser: streamI18n.tDateTimeParser,\n });\n if (!result || typeof result === 'number') {\n return JSON.stringify(value);\n }\n return result;\n },\n};\n\nexport const defaultTranslatorFunction: TFunction = <tResult = string>(key: tResult) =>\n key;\n\nexport const defaultDateTimeParser = (input?: TDateTimeParserInput) => Dayjs(input);\n\nexport const isLanguageSupported = (\n language: string,\n): language is SupportedTranslations => {\n const translations = [\n 'de',\n 'en',\n 'es',\n 'fr',\n 'hi',\n 'it',\n 'ja',\n 'ko',\n 'nl',\n 'pt',\n 'ru',\n 'tr',\n ];\n return translations.some((translation) => language === translation);\n};\n", "import React, { createContext, PropsWithChildren, useContext } from 'react';\n\nimport type { TriggerSettings } from '../components/MessageInput/DefaultTriggerProvider';\nimport type { CooldownTimerState, MessageInputProps } from '../components/MessageInput';\nimport type {\n CommandsListState,\n MentionsListState,\n MessageInputHookProps,\n MessageInputState,\n} from '../components/MessageInput/hooks/useMessageInputState';\n\nimport type { CustomTrigger, DefaultStreamChatGenerics } from '../types/types';\n\nexport type MessageInputContextValue<\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n> = MessageInputState<StreamChatGenerics> &\n MessageInputHookProps<StreamChatGenerics> &\n Omit<MessageInputProps<StreamChatGenerics, V>, 'Input'> &\n CooldownTimerState & {\n autocompleteTriggers?: TriggerSettings<StreamChatGenerics, V>;\n } & CommandsListState &\n MentionsListState;\n\nexport const MessageInputContext = createContext<\n (MessageInputState & MessageInputHookProps) | undefined\n>(undefined);\n\nexport const MessageInputContextProvider = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n>({\n children,\n value,\n}: PropsWithChildren<{\n value: MessageInputContextValue<StreamChatGenerics, V>;\n}>) => (\n <MessageInputContext.Provider value={value as MessageInputContextValue}>\n {children}\n </MessageInputContext.Provider>\n);\n\nexport const useMessageInputContext = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n>(\n componentName?: string,\n) => {\n const contextValue = useContext(MessageInputContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageInputContext hook was called outside of the MessageInputContext provider. Make sure this hook is called within the MessageInput's UI component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageInputContextValue<StreamChatGenerics, V>;\n }\n\n return contextValue as MessageInputContextValue<StreamChatGenerics, V>;\n};\n", "import React from 'react';\n\nexport const EmojiPickerIcon = () => (\n <svg\n preserveAspectRatio='xMinYMin'\n viewBox='0 0 28 28'\n width='100%'\n xmlns='http://www.w3.org/2000/svg'\n >\n <g clipRule='evenodd' fillRule='evenodd'>\n <path d='M14 4.4C8.6 4.4 4.4 8.6 4.4 14c0 5.4 4.2 9.6 9.6 9.6c5.4 0 9.6-4.2 9.6-9.6c0-5.4-4.2-9.6-9.6-9.6zM2 14c0-6.6 5.4-12 12-12s12 5.4 12 12s-5.4 12-12 12s-12-5.4-12-12zM12.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM18.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM8.6 15.4c.6-.4 1.2-.2 1.6.2c.6.8 1.6 1.8 3 2c1.2.4 2.8.2 4.8-2c.4-.4 1.2-.6 1.6 0c.4.4.6 1.2 0 1.6c-2.2 2.6-4.8 3.4-7 3c-2-.4-3.6-1.8-4.4-3c-.4-.6-.2-1.2.4-1.8z'></path>\n </g>\n </svg>\n);\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_react", "import_dayjs", "Dayjs", "Dayjs", "calendar", "localizedFormat", "React", "import_react", "import_react", "React", "React", "Picker"]
7
7
  }
@@ -108,7 +108,9 @@ var EmojiPicker = (props) => {
108
108
  const { t } = useTranslationContext("EmojiPicker");
109
109
  const { insertText, textareaRef } = useMessageInputContext("EmojiPicker");
110
110
  const [displayPicker, setDisplayPicker] = (0, import_react4.useState)(false);
111
- const [referenceElement, setReferenceElement] = (0, import_react4.useState)(null);
111
+ const [referenceElement, setReferenceElement] = (0, import_react4.useState)(
112
+ null
113
+ );
112
114
  const [popperElement, setPopperElement] = (0, import_react4.useState)(null);
113
115
  const { attributes, styles } = (0, import_react_popper.usePopper)(referenceElement, popperElement, {
114
116
  placement: "top-end",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/plugins/Emojis/index.ts", "../../../src/plugins/Emojis/EmojiPicker.tsx", "../../../src/context/TranslationContext.tsx", "../../../src/i18n/utils.ts", "../../../src/context/MessageInputContext.tsx", "../../../src/plugins/Emojis/icons.tsx"],
4
- "sourcesContent": ["export * from './EmojiPicker';\nexport { EmojiPickerIcon } from './icons';\n", "/* eslint-disable typescript-sort-keys/interface */\nimport React, { useEffect, useState } from 'react';\nimport { usePopper } from 'react-popper';\nimport Picker from '@emoji-mart/react';\n\nimport type { Options } from '@popperjs/core';\n\nimport { useMessageInputContext, useTranslationContext } from '../../context';\nimport { EmojiPickerIcon } from './icons';\n\nconst isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;\n\nexport type EmojiPickerProps = {\n ButtonIconComponent?: React.ComponentType;\n buttonClassName?: string;\n pickerContainerClassName?: string;\n wrapperClassName?: string;\n closeOnEmojiSelect?: boolean;\n /**\n * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.5.2#options--props) to be\n * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.5.2#-picker) component\n */\n pickerProps?: Partial<{ theme: 'auto' | 'light' | 'dark' } & Record<string, unknown>>;\n /**\n * [React Popper options](https://popper.js.org/docs/v2/constructors/#options) to be\n * passed down to the [react-popper `usePopper`](https://popper.js.org/react-popper/v2/hook/) hook\n */\n popperOptions?: Partial<Options>;\n};\n\nconst classNames: EmojiPickerProps = {\n buttonClassName: 'str-chat__emoji-picker-button',\n pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',\n wrapperClassName: 'str-chat__message-textarea-emoji-picker',\n};\n\nexport const EmojiPicker = (props: EmojiPickerProps) => {\n const { t } = useTranslationContext('EmojiPicker');\n const { insertText, textareaRef } = useMessageInputContext('EmojiPicker');\n const [displayPicker, setDisplayPicker] = useState(false);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);\n const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);\n const { attributes, styles } = usePopper(referenceElement, popperElement, {\n placement: 'top-end',\n ...props.popperOptions,\n });\n\n const { buttonClassName, pickerContainerClassName, wrapperClassName } = classNames;\n\n const { ButtonIconComponent = EmojiPickerIcon } = props;\n\n useEffect(() => {\n if (!popperElement || !referenceElement) return;\n\n const handlePointerDown = (e: PointerEvent) => {\n const target = e.target as HTMLElement;\n\n const rootNode = target.getRootNode();\n\n if (\n popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||\n referenceElement.contains(target)\n ) {\n return;\n }\n\n setDisplayPicker(false);\n };\n\n window.addEventListener('pointerdown', handlePointerDown);\n return () => window.removeEventListener('pointerdown', handlePointerDown);\n }, [referenceElement, popperElement]);\n\n return (\n <div className={props.wrapperClassName ?? wrapperClassName}>\n {displayPicker && (\n <div\n className={props.pickerContainerClassName ?? pickerContainerClassName}\n style={styles.popper}\n {...attributes.popper}\n ref={setPopperElement}\n >\n <Picker\n data={async () => (await import('@emoji-mart/data')).default}\n onEmojiSelect={(e: { native: string }) => {\n insertText(e.native);\n textareaRef.current?.focus();\n if (props.closeOnEmojiSelect) {\n setDisplayPicker(false);\n }\n }}\n {...props.pickerProps}\n />\n </div>\n )}\n <button\n aria-expanded={displayPicker}\n aria-label={t('aria/Emoji picker')}\n className={props.buttonClassName ?? buttonClassName}\n onClick={() => setDisplayPicker((cv) => !cv)}\n ref={setReferenceElement}\n type='button'\n >\n {ButtonIconComponent && <ButtonIconComponent />}\n </button>\n </div>\n );\n};\n", "import React, { PropsWithChildren, useContext } from 'react';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar';\nimport localizedFormat from 'dayjs/plugin/localizedFormat';\n\nimport { getDisplayName } from './utils/getDisplayName';\nimport { defaultDateTimeParser, defaultTranslatorFunction } from '../i18n/utils';\n\nimport type { TFunction } from 'i18next';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { UnknownType } from '../types/types';\nimport type { TDateTimeParser } from '../i18n/types';\n\nDayjs.extend(calendar);\nDayjs.extend(localizedFormat);\n\nexport type TranslationContextValue = {\n t: TFunction;\n tDateTimeParser: TDateTimeParser;\n userLanguage: TranslationLanguages;\n};\n\nexport const TranslationContext = React.createContext<TranslationContextValue>({\n t: defaultTranslatorFunction,\n tDateTimeParser: defaultDateTimeParser,\n userLanguage: 'en',\n});\n\nexport const TranslationProvider = ({\n children,\n value,\n}: PropsWithChildren<{ value: TranslationContextValue }>) => (\n <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>\n);\n\nexport const useTranslationContext = (componentName?: string) => {\n const contextValue = useContext(TranslationContext);\n\n if (!contextValue) {\n console.warn(\n `The useTranslationContext hook was called outside of the TranslationContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as TranslationContextValue;\n }\n\n return contextValue;\n};\n\nexport const withTranslationContext = <P extends UnknownType>(\n Component: React.ComponentType<P>,\n) => {\n const WithTranslationContextComponent = (props: Omit<P, keyof TranslationContextValue>) => {\n const translationContext = useTranslationContext();\n\n return <Component {...(props as P)} {...translationContext} />;\n };\n\n WithTranslationContextComponent.displayName = `WithTranslationContext${getDisplayName(\n Component,\n )}`;\n\n return WithTranslationContextComponent;\n};\n", "import Dayjs from 'dayjs';\n\nimport type { TFunction } from 'i18next';\nimport type { Moment } from 'moment-timezone';\nimport type {\n DateFormatterOptions,\n PredefinedFormatters,\n SupportedTranslations,\n TDateTimeParserInput,\n TDateTimeParserOutput,\n TimestampFormatterOptions,\n} from './types';\n\nexport const notValidDateWarning =\n 'MessageTimestamp was called without a message, or message has invalid created_at date.';\nexport const noParsingFunctionWarning =\n 'MessageTimestamp was called but there is no datetime parsing function available';\n\nexport const isNumberOrString = (output: TDateTimeParserOutput): output is number | string =>\n typeof output === 'string' || typeof output === 'number';\n\nexport const isDayOrMoment = (output: TDateTimeParserOutput): output is Dayjs.Dayjs | Moment =>\n !!(output as Dayjs.Dayjs | Moment)?.isSame;\n\nexport const isDate = (output: TDateTimeParserOutput): output is Date =>\n !!(output as Date)?.getMonth;\n\nexport function getDateString({\n calendar,\n calendarFormats,\n format,\n formatDate,\n messageCreatedAt,\n t,\n tDateTimeParser,\n timestampTranslationKey,\n}: DateFormatterOptions): string | number | null {\n if (\n !messageCreatedAt ||\n (typeof messageCreatedAt === 'string' && !Date.parse(messageCreatedAt))\n ) {\n console.warn(notValidDateWarning);\n return null;\n }\n\n if (typeof formatDate === 'function') {\n return formatDate(new Date(messageCreatedAt));\n }\n\n if (t && timestampTranslationKey) {\n const options: TimestampFormatterOptions = {};\n if (typeof calendar !== 'undefined' && calendar !== null) options.calendar = calendar;\n if (typeof calendarFormats !== 'undefined' && calendarFormats !== null)\n options.calendarFormats = calendarFormats;\n if (typeof format !== 'undefined' && format !== null) options.format = format;\n\n const translatedTimestamp = t(timestampTranslationKey, {\n ...options,\n timestamp: new Date(messageCreatedAt),\n });\n const translationKeyFound = timestampTranslationKey !== translatedTimestamp;\n if (translationKeyFound) return translatedTimestamp;\n }\n\n if (!tDateTimeParser) {\n console.warn(noParsingFunctionWarning);\n return null;\n }\n\n const parsedTime = tDateTimeParser(messageCreatedAt);\n\n if (isDayOrMoment(parsedTime)) {\n /**\n * parsedTime.calendar is guaranteed on the type but is only\n * available when a user calls dayjs.extend(calendar)\n */\n return calendar && parsedTime.calendar\n ? parsedTime.calendar(undefined, calendarFormats || undefined)\n : parsedTime.format(format || undefined);\n }\n\n if (isDate(parsedTime)) {\n return parsedTime.toDateString();\n }\n\n if (isNumberOrString(parsedTime)) {\n return parsedTime;\n }\n\n return null;\n}\n\nexport const predefinedFormatters: PredefinedFormatters = {\n timestampFormatter: (streamI18n) => (\n value,\n _,\n {\n calendarFormats,\n ...options\n }: Pick<TimestampFormatterOptions, 'calendar' | 'format'> & {\n calendarFormats?: Record<string, string> | string;\n },\n ) => {\n let parsedCalendarFormats;\n try {\n if (!options.calendar) {\n parsedCalendarFormats = {};\n } else if (typeof calendarFormats === 'string') {\n parsedCalendarFormats = JSON.parse(calendarFormats);\n } else if (typeof calendarFormats === 'object') {\n parsedCalendarFormats = calendarFormats;\n }\n } catch (e) {\n console.error('[TIMESTAMP FORMATTER]', e);\n }\n\n const result = getDateString({\n ...options,\n calendarFormats: parsedCalendarFormats,\n messageCreatedAt: value,\n tDateTimeParser: streamI18n.tDateTimeParser,\n });\n if (!result || typeof result === 'number') {\n return JSON.stringify(value);\n }\n return result;\n },\n};\n\nexport const defaultTranslatorFunction: TFunction = <tResult = string>(key: tResult) => key;\n\nexport const defaultDateTimeParser = (input?: TDateTimeParserInput) => Dayjs(input);\n\nexport const isLanguageSupported = (language: string): language is SupportedTranslations => {\n const translations = ['de', 'en', 'es', 'fr', 'hi', 'it', 'ja', 'ko', 'nl', 'pt', 'ru', 'tr'];\n return translations.some((translation) => language === translation);\n};\n", "import React, { createContext, PropsWithChildren, useContext } from 'react';\n\nimport type { TriggerSettings } from '../components/MessageInput/DefaultTriggerProvider';\nimport type { CooldownTimerState, MessageInputProps } from '../components/MessageInput';\nimport type {\n CommandsListState,\n MentionsListState,\n MessageInputHookProps,\n MessageInputState,\n} from '../components/MessageInput/hooks/useMessageInputState';\n\nimport type { CustomTrigger, DefaultStreamChatGenerics } from '../types/types';\n\nexport type MessageInputContextValue<\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n> = MessageInputState<StreamChatGenerics> &\n MessageInputHookProps<StreamChatGenerics> &\n Omit<MessageInputProps<StreamChatGenerics, V>, 'Input'> &\n CooldownTimerState & {\n autocompleteTriggers?: TriggerSettings<StreamChatGenerics, V>;\n } & CommandsListState &\n MentionsListState;\n\nexport const MessageInputContext = createContext<\n (MessageInputState & MessageInputHookProps) | undefined\n>(undefined);\n\nexport const MessageInputContextProvider = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n>({\n children,\n value,\n}: PropsWithChildren<{\n value: MessageInputContextValue<StreamChatGenerics, V>;\n}>) => (\n <MessageInputContext.Provider value={value as MessageInputContextValue}>\n {children}\n </MessageInputContext.Provider>\n);\n\nexport const useMessageInputContext = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger\n>(\n componentName?: string,\n) => {\n const contextValue = useContext(MessageInputContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageInputContext hook was called outside of the MessageInputContext provider. Make sure this hook is called within the MessageInput's UI component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageInputContextValue<StreamChatGenerics, V>;\n }\n\n return contextValue as MessageInputContextValue<StreamChatGenerics, V>;\n};\n", "import React from 'react';\n\nexport const EmojiPickerIcon = () => (\n <svg\n preserveAspectRatio='xMinYMin'\n viewBox='0 0 28 28'\n width='100%'\n xmlns='http://www.w3.org/2000/svg'\n >\n <g clipRule='evenodd' fillRule='evenodd'>\n <path d='M14 4.4C8.6 4.4 4.4 8.6 4.4 14c0 5.4 4.2 9.6 9.6 9.6c5.4 0 9.6-4.2 9.6-9.6c0-5.4-4.2-9.6-9.6-9.6zM2 14c0-6.6 5.4-12 12-12s12 5.4 12 12s-5.4 12-12 12s-12-5.4-12-12zM12.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM18.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM8.6 15.4c.6-.4 1.2-.2 1.6.2c.6.8 1.6 1.8 3 2c1.2.4 2.8.2 4.8-2c.4-.4 1.2-.6 1.6 0c.4.4.6 1.2 0 1.6c-2.2 2.6-4.8 3.4-7 3c-2-.4-3.6-1.8-4.4-3c-.4-.6-.2-1.2.4-1.8z'></path>\n </g>\n </svg>\n);\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export * from './EmojiPicker';\nexport { EmojiPickerIcon } from './icons';\n", "import React, { useEffect, useState } from 'react';\nimport { usePopper } from 'react-popper';\nimport Picker from '@emoji-mart/react';\n\nimport type { Options } from '@popperjs/core';\n\nimport { useMessageInputContext, useTranslationContext } from '../../context';\nimport { EmojiPickerIcon } from './icons';\n\nconst isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;\n\nexport type EmojiPickerProps = {\n ButtonIconComponent?: React.ComponentType;\n buttonClassName?: string;\n pickerContainerClassName?: string;\n wrapperClassName?: string;\n closeOnEmojiSelect?: boolean;\n /**\n * Untyped [properties](https://github.com/missive/emoji-mart/tree/v5.5.2#options--props) to be\n * passed down to the [emoji-mart `Picker`](https://github.com/missive/emoji-mart/tree/v5.5.2#-picker) component\n */\n pickerProps?: Partial<{ theme: 'auto' | 'light' | 'dark' } & Record<string, unknown>>;\n /**\n * [React Popper options](https://popper.js.org/docs/v2/constructors/#options) to be\n * passed down to the [react-popper `usePopper`](https://popper.js.org/react-popper/v2/hook/) hook\n */\n popperOptions?: Partial<Options>;\n};\n\nconst classNames: EmojiPickerProps = {\n buttonClassName: 'str-chat__emoji-picker-button',\n pickerContainerClassName: 'str-chat__message-textarea-emoji-picker-container',\n wrapperClassName: 'str-chat__message-textarea-emoji-picker',\n};\n\nexport const EmojiPicker = (props: EmojiPickerProps) => {\n const { t } = useTranslationContext('EmojiPicker');\n const { insertText, textareaRef } = useMessageInputContext('EmojiPicker');\n const [displayPicker, setDisplayPicker] = useState(false);\n const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(\n null,\n );\n const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);\n const { attributes, styles } = usePopper(referenceElement, popperElement, {\n placement: 'top-end',\n ...props.popperOptions,\n });\n\n const { buttonClassName, pickerContainerClassName, wrapperClassName } = classNames;\n\n const { ButtonIconComponent = EmojiPickerIcon } = props;\n\n useEffect(() => {\n if (!popperElement || !referenceElement) return;\n\n const handlePointerDown = (e: PointerEvent) => {\n const target = e.target as HTMLElement;\n\n const rootNode = target.getRootNode();\n\n if (\n popperElement.contains(isShadowRoot(rootNode) ? rootNode.host : target) ||\n referenceElement.contains(target)\n ) {\n return;\n }\n\n setDisplayPicker(false);\n };\n\n window.addEventListener('pointerdown', handlePointerDown);\n return () => window.removeEventListener('pointerdown', handlePointerDown);\n }, [referenceElement, popperElement]);\n\n return (\n <div className={props.wrapperClassName ?? wrapperClassName}>\n {displayPicker && (\n <div\n className={props.pickerContainerClassName ?? pickerContainerClassName}\n style={styles.popper}\n {...attributes.popper}\n ref={setPopperElement}\n >\n <Picker\n data={async () => (await import('@emoji-mart/data')).default}\n onEmojiSelect={(e: { native: string }) => {\n insertText(e.native);\n textareaRef.current?.focus();\n if (props.closeOnEmojiSelect) {\n setDisplayPicker(false);\n }\n }}\n {...props.pickerProps}\n />\n </div>\n )}\n <button\n aria-expanded={displayPicker}\n aria-label={t('aria/Emoji picker')}\n className={props.buttonClassName ?? buttonClassName}\n onClick={() => setDisplayPicker((cv) => !cv)}\n ref={setReferenceElement}\n type='button'\n >\n {ButtonIconComponent && <ButtonIconComponent />}\n </button>\n </div>\n );\n};\n", "import React, { PropsWithChildren, useContext } from 'react';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar';\nimport localizedFormat from 'dayjs/plugin/localizedFormat';\n\nimport { getDisplayName } from './utils/getDisplayName';\nimport { defaultDateTimeParser, defaultTranslatorFunction } from '../i18n/utils';\n\nimport type { TFunction } from 'i18next';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { UnknownType } from '../types/types';\nimport type { TDateTimeParser } from '../i18n/types';\n\nDayjs.extend(calendar);\nDayjs.extend(localizedFormat);\n\nexport type TranslationContextValue = {\n t: TFunction;\n tDateTimeParser: TDateTimeParser;\n userLanguage: TranslationLanguages;\n};\n\nexport const TranslationContext = React.createContext<TranslationContextValue>({\n t: defaultTranslatorFunction,\n tDateTimeParser: defaultDateTimeParser,\n userLanguage: 'en',\n});\n\nexport const TranslationProvider = ({\n children,\n value,\n}: PropsWithChildren<{ value: TranslationContextValue }>) => (\n <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>\n);\n\nexport const useTranslationContext = (componentName?: string) => {\n const contextValue = useContext(TranslationContext);\n\n if (!contextValue) {\n console.warn(\n `The useTranslationContext hook was called outside of the TranslationContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as TranslationContextValue;\n }\n\n return contextValue;\n};\n\nexport const withTranslationContext = <P extends UnknownType>(\n Component: React.ComponentType<P>,\n) => {\n const WithTranslationContextComponent = (\n props: Omit<P, keyof TranslationContextValue>,\n ) => {\n const translationContext = useTranslationContext();\n\n return <Component {...(props as P)} {...translationContext} />;\n };\n\n WithTranslationContextComponent.displayName = `WithTranslationContext${getDisplayName(\n Component,\n )}`;\n\n return WithTranslationContextComponent;\n};\n", "import Dayjs from 'dayjs';\n\nimport type { TFunction } from 'i18next';\nimport type { Moment } from 'moment-timezone';\nimport type {\n DateFormatterOptions,\n PredefinedFormatters,\n SupportedTranslations,\n TDateTimeParserInput,\n TDateTimeParserOutput,\n TimestampFormatterOptions,\n} from './types';\n\nexport const notValidDateWarning =\n 'MessageTimestamp was called without a message, or message has invalid created_at date.';\nexport const noParsingFunctionWarning =\n 'MessageTimestamp was called but there is no datetime parsing function available';\n\nexport const isNumberOrString = (\n output: TDateTimeParserOutput,\n): output is number | string => typeof output === 'string' || typeof output === 'number';\n\nexport const isDayOrMoment = (\n output: TDateTimeParserOutput,\n): output is Dayjs.Dayjs | Moment => !!(output as Dayjs.Dayjs | Moment)?.isSame;\n\nexport const isDate = (output: TDateTimeParserOutput): output is Date =>\n !!(output as Date)?.getMonth;\n\nexport function getDateString({\n calendar,\n calendarFormats,\n format,\n formatDate,\n messageCreatedAt,\n t,\n tDateTimeParser,\n timestampTranslationKey,\n}: DateFormatterOptions): string | number | null {\n if (\n !messageCreatedAt ||\n (typeof messageCreatedAt === 'string' && !Date.parse(messageCreatedAt))\n ) {\n console.warn(notValidDateWarning);\n return null;\n }\n\n if (typeof formatDate === 'function') {\n return formatDate(new Date(messageCreatedAt));\n }\n\n if (t && timestampTranslationKey) {\n const options: TimestampFormatterOptions = {};\n if (typeof calendar !== 'undefined' && calendar !== null) options.calendar = calendar;\n if (typeof calendarFormats !== 'undefined' && calendarFormats !== null)\n options.calendarFormats = calendarFormats;\n if (typeof format !== 'undefined' && format !== null) options.format = format;\n\n const translatedTimestamp = t(timestampTranslationKey, {\n ...options,\n timestamp: new Date(messageCreatedAt),\n });\n const translationKeyFound = timestampTranslationKey !== translatedTimestamp;\n if (translationKeyFound) return translatedTimestamp;\n }\n\n if (!tDateTimeParser) {\n console.warn(noParsingFunctionWarning);\n return null;\n }\n\n const parsedTime = tDateTimeParser(messageCreatedAt);\n\n if (isDayOrMoment(parsedTime)) {\n /**\n * parsedTime.calendar is guaranteed on the type but is only\n * available when a user calls dayjs.extend(calendar)\n */\n return calendar && parsedTime.calendar\n ? parsedTime.calendar(undefined, calendarFormats || undefined)\n : parsedTime.format(format || undefined);\n }\n\n if (isDate(parsedTime)) {\n return parsedTime.toDateString();\n }\n\n if (isNumberOrString(parsedTime)) {\n return parsedTime;\n }\n\n return null;\n}\n\nexport const predefinedFormatters: PredefinedFormatters = {\n timestampFormatter:\n (streamI18n) =>\n (\n value,\n _,\n {\n calendarFormats,\n ...options\n }: Pick<TimestampFormatterOptions, 'calendar' | 'format'> & {\n calendarFormats?: Record<string, string> | string;\n },\n ) => {\n let parsedCalendarFormats;\n try {\n if (!options.calendar) {\n parsedCalendarFormats = {};\n } else if (typeof calendarFormats === 'string') {\n parsedCalendarFormats = JSON.parse(calendarFormats);\n } else if (typeof calendarFormats === 'object') {\n parsedCalendarFormats = calendarFormats;\n }\n } catch (e) {\n console.error('[TIMESTAMP FORMATTER]', e);\n }\n\n const result = getDateString({\n ...options,\n calendarFormats: parsedCalendarFormats,\n messageCreatedAt: value,\n tDateTimeParser: streamI18n.tDateTimeParser,\n });\n if (!result || typeof result === 'number') {\n return JSON.stringify(value);\n }\n return result;\n },\n};\n\nexport const defaultTranslatorFunction: TFunction = <tResult = string>(key: tResult) =>\n key;\n\nexport const defaultDateTimeParser = (input?: TDateTimeParserInput) => Dayjs(input);\n\nexport const isLanguageSupported = (\n language: string,\n): language is SupportedTranslations => {\n const translations = [\n 'de',\n 'en',\n 'es',\n 'fr',\n 'hi',\n 'it',\n 'ja',\n 'ko',\n 'nl',\n 'pt',\n 'ru',\n 'tr',\n ];\n return translations.some((translation) => language === translation);\n};\n", "import React, { createContext, PropsWithChildren, useContext } from 'react';\n\nimport type { TriggerSettings } from '../components/MessageInput/DefaultTriggerProvider';\nimport type { CooldownTimerState, MessageInputProps } from '../components/MessageInput';\nimport type {\n CommandsListState,\n MentionsListState,\n MessageInputHookProps,\n MessageInputState,\n} from '../components/MessageInput/hooks/useMessageInputState';\n\nimport type { CustomTrigger, DefaultStreamChatGenerics } from '../types/types';\n\nexport type MessageInputContextValue<\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n> = MessageInputState<StreamChatGenerics> &\n MessageInputHookProps<StreamChatGenerics> &\n Omit<MessageInputProps<StreamChatGenerics, V>, 'Input'> &\n CooldownTimerState & {\n autocompleteTriggers?: TriggerSettings<StreamChatGenerics, V>;\n } & CommandsListState &\n MentionsListState;\n\nexport const MessageInputContext = createContext<\n (MessageInputState & MessageInputHookProps) | undefined\n>(undefined);\n\nexport const MessageInputContextProvider = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n>({\n children,\n value,\n}: PropsWithChildren<{\n value: MessageInputContextValue<StreamChatGenerics, V>;\n}>) => (\n <MessageInputContext.Provider value={value as MessageInputContextValue}>\n {children}\n </MessageInputContext.Provider>\n);\n\nexport const useMessageInputContext = <\n StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,\n V extends CustomTrigger = CustomTrigger,\n>(\n componentName?: string,\n) => {\n const contextValue = useContext(MessageInputContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageInputContext hook was called outside of the MessageInputContext provider. Make sure this hook is called within the MessageInput's UI component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageInputContextValue<StreamChatGenerics, V>;\n }\n\n return contextValue as MessageInputContextValue<StreamChatGenerics, V>;\n};\n", "import React from 'react';\n\nexport const EmojiPickerIcon = () => (\n <svg\n preserveAspectRatio='xMinYMin'\n viewBox='0 0 28 28'\n width='100%'\n xmlns='http://www.w3.org/2000/svg'\n >\n <g clipRule='evenodd' fillRule='evenodd'>\n <path d='M14 4.4C8.6 4.4 4.4 8.6 4.4 14c0 5.4 4.2 9.6 9.6 9.6c5.4 0 9.6-4.2 9.6-9.6c0-5.4-4.2-9.6-9.6-9.6zM2 14c0-6.6 5.4-12 12-12s12 5.4 12 12s-5.4 12-12 12s-12-5.4-12-12zM12.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM18.8 11c0 1-.8 1.8-1.8 1.8s-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8s1.8.8 1.8 1.8zM8.6 15.4c.6-.4 1.2-.2 1.6.2c.6.8 1.6 1.8 3 2c1.2.4 2.8.2 4.8-2c.4-.4 1.2-.6 1.6 0c.4.4.6 1.2 0 1.6c-2.2 2.6-4.8 3.4-7 3c-2-.4-3.6-1.8-4.4-3c-.4-.6-.2-1.2.4-1.8z'></path>\n </g>\n </svg>\n);\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_react", "import_dayjs", "Dayjs", "Dayjs", "calendar", "localizedFormat", "React", "import_react", "import_react", "React", "React", "Picker"]
7
7
  }
@@ -80,9 +80,10 @@ var float32ArrayToInt16Array = (float32Arr) => {
80
80
  }
81
81
  return int16Arr;
82
82
  };
83
- var splitDataByChannel = (audioBuffer) => Array.from({ length: audioBuffer.numberOfChannels }, (_, i) => audioBuffer.getChannelData(i)).map(
84
- float32ArrayToInt16Array
85
- );
83
+ var splitDataByChannel = (audioBuffer) => Array.from(
84
+ { length: audioBuffer.numberOfChannels },
85
+ (_, i) => audioBuffer.getChannelData(i)
86
+ ).map(float32ArrayToInt16Array);
86
87
  async function encodeToMp3(file, sampleRate) {
87
88
  const lameJs = await import("@breezystack/lamejs");
88
89
  const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);
@@ -95,7 +96,9 @@ async function encodeToMp3(file, sampleRate) {
95
96
  const [leftChannelBlock, rightChannelBlock] = dataByChannel.map(
96
97
  (channel) => channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK)
97
98
  );
98
- dataBuffer.push(new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)));
99
+ dataBuffer.push(
100
+ new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock))
101
+ );
99
102
  remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;
100
103
  }
101
104
  const lastBlock = mp3Encoder.flush();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/plugins/encoders/mp3.ts", "../../../src/components/ReactFileUtilities/utils.ts", "../../../src/components/MediaRecorder/transcode/audioProcessing.ts"],
4
- "sourcesContent": ["import {\n renderAudio,\n toAudioBuffer,\n} from '../../components/MediaRecorder/transcode/audioProcessing';\n\nconst ENCODING_BIT_RATE = 128; // kbps;\nconst COUNT_SAMPLES_PER_ENCODED_BLOCK = 1152;\n\nconst float32ArrayToInt16Array = (float32Arr: Float32Array) => {\n const int16Arr = new Int16Array(float32Arr.length);\n for (let i = 0; i < float32Arr.length; i++) {\n const float32Value = float32Arr[i];\n // Clamp the float value between -1 and 1\n const clampedValue = Math.max(-1, Math.min(1, float32Value));\n // Convert the float value to a signed 16-bit integer\n int16Arr[i] = Math.round(clampedValue * 32767);\n }\n return int16Arr;\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n Array.from({ length: audioBuffer.numberOfChannels }, (_, i) => audioBuffer.getChannelData(i)).map(\n float32ArrayToInt16Array,\n );\n\nexport async function encodeToMp3(file: File, sampleRate: number) {\n const lameJs = await import('@breezystack/lamejs');\n const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n const channelCount = audioBuffer.numberOfChannels;\n const dataByChannel = splitDataByChannel(audioBuffer);\n const mp3Encoder = new lameJs.Mp3Encoder(channelCount, sampleRate, ENCODING_BIT_RATE);\n\n const dataBuffer: Int8Array[] = [];\n let remaining = dataByChannel[0].length;\n for (\n let i = 0;\n remaining >= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n i += COUNT_SAMPLES_PER_ENCODED_BLOCK\n ) {\n const [leftChannelBlock, rightChannelBlock] = dataByChannel.map((channel) =>\n channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK),\n );\n dataBuffer.push(new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)));\n remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n }\n\n const lastBlock = mp3Encoder.flush();\n if (lastBlock.length) dataBuffer.push(new Int8Array(lastBlock));\n return new Blob(dataBuffer, { type: 'audio/mp3;sbu_type=voice' });\n}\n", "import { FileLike, RecordedMediaType } from './types';\nimport { ChangeEvent, useCallback } from 'react';\n\nexport const useHandleFileChangeWrapper = (\n resetOnChange = false,\n handler?: (files: Array<File>) => void,\n) =>\n useCallback(\n ({ currentTarget }: ChangeEvent<HTMLInputElement>) => {\n const { files } = currentTarget;\n\n if (!files) return;\n\n try {\n handler?.(Array.from(files));\n } catch (error) {\n console.error(error);\n }\n\n if (resetOnChange) currentTarget.value = '';\n },\n [handler, resetOnChange],\n );\n\nexport function dataTransferItemsHaveFiles(items?: DataTransferItem[]): boolean {\n if (!items || !items.length) {\n return false;\n }\n for (const item of items) {\n if (item.kind === 'file' || item.type === 'text/html') {\n return true;\n }\n }\n return false;\n}\n\nexport async function dataTransferItemsToFiles(items?: DataTransferItem[]): Promise<FileLike[]> {\n if (!items || !items.length) {\n return [];\n }\n\n // If there are files inside the DataTransferItem prefer those\n const fileLikes = getFileLikes(items);\n if (fileLikes.length) {\n return fileLikes;\n }\n\n // Otherwise extract images from html\n const blobPromises = [];\n for (const item of items) {\n if (item.type === 'text/html') {\n blobPromises.push(\n new Promise<void>((accept) => {\n item.getAsString(async (s) => {\n const imagePromises = extractImageSources(s).map((src) =>\n getImageSource(fileLikes, src),\n );\n\n await Promise.all(imagePromises);\n accept();\n });\n }),\n );\n }\n }\n await Promise.all(blobPromises);\n return fileLikes;\n}\n\nfunction getFileLikes(items: DataTransferItem[]) {\n const fileLikes = [];\n for (const item of items) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) {\n fileLikes.push(file);\n }\n }\n }\n return fileLikes;\n}\n\nasync function getImageSource(fileLikes: FileLike[], src: string) {\n let res;\n try {\n res = await fetch(src);\n } catch (e) {\n return;\n }\n const contentType = res.headers.get('Content-type') || 'application/octet-stream';\n const buf = await res.arrayBuffer();\n const blob = new Blob([buf], { type: contentType });\n fileLikes.push(blob);\n}\n\nconst extractImageSources = (s: string) => {\n const imageTags = new DOMParser().parseFromString(s, 'text/html').getElementsByTagName('img');\n return Array.from(imageTags, (tag) => tag.src).filter((tag) => tag);\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n obj instanceof Blob && !(obj instanceof File);\n\nexport const createFileFromBlobs = ({\n blobsArray,\n fileName,\n mimeType,\n}: {\n blobsArray: Blob[];\n fileName: string;\n mimeType: string;\n}) => {\n const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n const match = mimeType.match(/\\/([^/;]+)/);\n return match && match[1];\n};\n\nexport const getRecordedMediaTypeFromMimeType = (mimeType: string): RecordedMediaType | null => {\n const match = mimeType.match(/^(audio|video)\\/.*$/);\n return match && (match[1] as RecordedMediaType);\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = () => {\n resolve(fileReader.result as ArrayBuffer);\n };\n\n fileReader.onerror = () => {\n reject(fileReader.error);\n };\n\n fileReader.readAsArrayBuffer(file);\n });\n\nexport const generateFileName = (mimeType: string) =>\n `file_${new Date().toISOString()}.${getExtensionFromMimeType(mimeType)}`;\n", "import { readFileAsArrayBuffer } from '../../ReactFileUtilities';\n\n/**\n * In the context of resampling audio data, AudioContext is used to decode the input audio file into an AudioBuffer,\n * which is a fundamental data structure representing audio data.\n * @param file\n */\nexport const toAudioBuffer = async (file: File) => {\n const audioCtx = new AudioContext();\n\n const arrayBuffer = await readFileAsArrayBuffer(file);\n const decodedData = await audioCtx.decodeAudioData(arrayBuffer);\n if (audioCtx.state !== 'closed') await audioCtx.close();\n return decodedData;\n};\n\n/**\n * OfflineAudioContext is a specialized type of AudioContext that does not render audio in real-time and is used for offline audio processing tasks.\n * It allows performing audio processing and rendering without actually playing the audio through speakers or outputting it to a destination.\n * In the context of resampling audio data, OfflineAudioContext is used to resample the decoded AudioBuffer from a file to the desired sample rate.\n * It provides more flexibility and control over audio processing, as it can operate at different sample rates and durations compared to real-time audio contexts.\n * @param audioBuffer\n * @param sampleRate\n */\nexport const renderAudio = async (audioBuffer: AudioBuffer, sampleRate: number) => {\n const offlineAudioCtx = new OfflineAudioContext(\n audioBuffer.numberOfChannels,\n audioBuffer.duration * sampleRate,\n sampleRate,\n );\n const source = offlineAudioCtx.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(offlineAudioCtx.destination);\n source.start();\n\n return await offlineAudioCtx.startRendering();\n};\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,mBAAyC;AA6HlC,IAAM,wBAAwB,CAAC,SACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,aAAa,IAAI,WAAW;AAClC,aAAW,SAAS,MAAM;AACxB,YAAQ,WAAW,MAAqB;AAAA,EAC1C;AAEA,aAAW,UAAU,MAAM;AACzB,WAAO,WAAW,KAAK;AAAA,EACzB;AAEA,aAAW,kBAAkB,IAAI;AACnC,CAAC;;;ACnII,IAAM,gBAAgB,OAAO,SAAe;AACjD,QAAM,WAAW,IAAI,aAAa;AAElC,QAAM,cAAc,MAAM,sBAAsB,IAAI;AACpD,QAAM,cAAc,MAAM,SAAS,gBAAgB,WAAW;AAC9D,MAAI,SAAS,UAAU,SAAU,OAAM,SAAS,MAAM;AACtD,SAAO;AACT;AAUO,IAAM,cAAc,OAAO,aAA0B,eAAuB;AACjF,QAAM,kBAAkB,IAAI;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY,WAAW;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,mBAAmB;AAClD,SAAO,SAAS;AAChB,SAAO,QAAQ,gBAAgB,WAAW;AAC1C,SAAO,MAAM;AAEb,SAAO,MAAM,gBAAgB,eAAe;AAC9C;;;AF/BA,IAAM,oBAAoB;AAC1B,IAAM,kCAAkC;AAExC,IAAM,2BAA2B,CAAC,eAA6B;AAC7D,QAAM,WAAW,IAAI,WAAW,WAAW,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,eAAe,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,YAAY,CAAC;AAE3D,aAAS,CAAC,IAAI,KAAK,MAAM,eAAe,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,gBAC1B,MAAM,KAAK,EAAE,QAAQ,YAAY,iBAAiB,GAAG,CAAC,GAAG,MAAM,YAAY,eAAe,CAAC,CAAC,EAAE;AAAA,EAC5F;AACF;AAEF,eAAsB,YAAY,MAAY,YAAoB;AAChE,QAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,QAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;AAC3E,QAAM,eAAe,YAAY;AACjC,QAAM,gBAAgB,mBAAmB,WAAW;AACpD,QAAM,aAAa,IAAI,OAAO,WAAW,cAAc,YAAY,iBAAiB;AAEpF,QAAM,aAA0B,CAAC;AACjC,MAAI,YAAY,cAAc,CAAC,EAAE;AACjC,WACM,IAAI,GACR,aAAa,iCACb,KAAK,iCACL;AACA,UAAM,CAAC,kBAAkB,iBAAiB,IAAI,cAAc;AAAA,MAAI,CAAC,YAC/D,QAAQ,SAAS,GAAG,IAAI,+BAA+B;AAAA,IACzD;AACA,eAAW,KAAK,IAAI,UAAU,WAAW,aAAa,kBAAkB,iBAAiB,CAAC,CAAC;AAC3F,iBAAa;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UAAU,OAAQ,YAAW,KAAK,IAAI,UAAU,SAAS,CAAC;AAC9D,SAAO,IAAI,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClE;",
4
+ "sourcesContent": ["import {\n renderAudio,\n toAudioBuffer,\n} from '../../components/MediaRecorder/transcode/audioProcessing';\n\nconst ENCODING_BIT_RATE = 128; // kbps;\nconst COUNT_SAMPLES_PER_ENCODED_BLOCK = 1152;\n\nconst float32ArrayToInt16Array = (float32Arr: Float32Array) => {\n const int16Arr = new Int16Array(float32Arr.length);\n for (let i = 0; i < float32Arr.length; i++) {\n const float32Value = float32Arr[i];\n // Clamp the float value between -1 and 1\n const clampedValue = Math.max(-1, Math.min(1, float32Value));\n // Convert the float value to a signed 16-bit integer\n int16Arr[i] = Math.round(clampedValue * 32767);\n }\n return int16Arr;\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n Array.from({ length: audioBuffer.numberOfChannels }, (_, i) =>\n audioBuffer.getChannelData(i),\n ).map(float32ArrayToInt16Array);\n\nexport async function encodeToMp3(file: File, sampleRate: number) {\n const lameJs = await import('@breezystack/lamejs');\n const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n const channelCount = audioBuffer.numberOfChannels;\n const dataByChannel = splitDataByChannel(audioBuffer);\n const mp3Encoder = new lameJs.Mp3Encoder(channelCount, sampleRate, ENCODING_BIT_RATE);\n\n const dataBuffer: Int8Array[] = [];\n let remaining = dataByChannel[0].length;\n for (\n let i = 0;\n remaining >= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n i += COUNT_SAMPLES_PER_ENCODED_BLOCK\n ) {\n const [leftChannelBlock, rightChannelBlock] = dataByChannel.map((channel) =>\n channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK),\n );\n dataBuffer.push(\n new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)),\n );\n remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n }\n\n const lastBlock = mp3Encoder.flush();\n if (lastBlock.length) dataBuffer.push(new Int8Array(lastBlock));\n return new Blob(dataBuffer, { type: 'audio/mp3;sbu_type=voice' });\n}\n", "import { FileLike, RecordedMediaType } from './types';\nimport { ChangeEvent, useCallback } from 'react';\n\nexport const useHandleFileChangeWrapper = (\n resetOnChange = false,\n handler?: (files: Array<File>) => void,\n) =>\n useCallback(\n ({ currentTarget }: ChangeEvent<HTMLInputElement>) => {\n const { files } = currentTarget;\n\n if (!files) return;\n\n try {\n handler?.(Array.from(files));\n } catch (error) {\n console.error(error);\n }\n\n if (resetOnChange) currentTarget.value = '';\n },\n [handler, resetOnChange],\n );\n\nexport function dataTransferItemsHaveFiles(items?: DataTransferItem[]): boolean {\n if (!items || !items.length) {\n return false;\n }\n for (const item of items) {\n if (item.kind === 'file' || item.type === 'text/html') {\n return true;\n }\n }\n return false;\n}\n\nexport async function dataTransferItemsToFiles(\n items?: DataTransferItem[],\n): Promise<FileLike[]> {\n if (!items || !items.length) {\n return [];\n }\n\n // If there are files inside the DataTransferItem prefer those\n const fileLikes = getFileLikes(items);\n if (fileLikes.length) {\n return fileLikes;\n }\n\n // Otherwise extract images from html\n const blobPromises = [];\n for (const item of items) {\n if (item.type === 'text/html') {\n blobPromises.push(\n new Promise<void>((accept) => {\n item.getAsString(async (s) => {\n const imagePromises = extractImageSources(s).map((src) =>\n getImageSource(fileLikes, src),\n );\n\n await Promise.all(imagePromises);\n accept();\n });\n }),\n );\n }\n }\n await Promise.all(blobPromises);\n return fileLikes;\n}\n\nfunction getFileLikes(items: DataTransferItem[]) {\n const fileLikes = [];\n for (const item of items) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) {\n fileLikes.push(file);\n }\n }\n }\n return fileLikes;\n}\n\nasync function getImageSource(fileLikes: FileLike[], src: string) {\n let res;\n try {\n res = await fetch(src);\n } catch (e) {\n return;\n }\n const contentType = res.headers.get('Content-type') || 'application/octet-stream';\n const buf = await res.arrayBuffer();\n const blob = new Blob([buf], { type: contentType });\n fileLikes.push(blob);\n}\n\nconst extractImageSources = (s: string) => {\n const imageTags = new DOMParser()\n .parseFromString(s, 'text/html')\n .getElementsByTagName('img');\n return Array.from(imageTags, (tag) => tag.src).filter((tag) => tag);\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n obj instanceof Blob && !(obj instanceof File);\n\nexport const createFileFromBlobs = ({\n blobsArray,\n fileName,\n mimeType,\n}: {\n blobsArray: Blob[];\n fileName: string;\n mimeType: string;\n}) => {\n const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n const match = mimeType.match(/\\/([^/;]+)/);\n return match && match[1];\n};\n\nexport const getRecordedMediaTypeFromMimeType = (\n mimeType: string,\n): RecordedMediaType | null => {\n const match = mimeType.match(/^(audio|video)\\/.*$/);\n return match && (match[1] as RecordedMediaType);\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = () => {\n resolve(fileReader.result as ArrayBuffer);\n };\n\n fileReader.onerror = () => {\n reject(fileReader.error);\n };\n\n fileReader.readAsArrayBuffer(file);\n });\n\nexport const generateFileName = (mimeType: string) =>\n `file_${new Date().toISOString()}.${getExtensionFromMimeType(mimeType)}`;\n", "import { readFileAsArrayBuffer } from '../../ReactFileUtilities';\n\n/**\n * In the context of resampling audio data, AudioContext is used to decode the input audio file into an AudioBuffer,\n * which is a fundamental data structure representing audio data.\n * @param file\n */\nexport const toAudioBuffer = async (file: File) => {\n const audioCtx = new AudioContext();\n\n const arrayBuffer = await readFileAsArrayBuffer(file);\n const decodedData = await audioCtx.decodeAudioData(arrayBuffer);\n if (audioCtx.state !== 'closed') await audioCtx.close();\n return decodedData;\n};\n\n/**\n * OfflineAudioContext is a specialized type of AudioContext that does not render audio in real-time and is used for offline audio processing tasks.\n * It allows performing audio processing and rendering without actually playing the audio through speakers or outputting it to a destination.\n * In the context of resampling audio data, OfflineAudioContext is used to resample the decoded AudioBuffer from a file to the desired sample rate.\n * It provides more flexibility and control over audio processing, as it can operate at different sample rates and durations compared to real-time audio contexts.\n * @param audioBuffer\n * @param sampleRate\n */\nexport const renderAudio = async (audioBuffer: AudioBuffer, sampleRate: number) => {\n const offlineAudioCtx = new OfflineAudioContext(\n audioBuffer.numberOfChannels,\n audioBuffer.duration * sampleRate,\n sampleRate,\n );\n const source = offlineAudioCtx.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(offlineAudioCtx.destination);\n source.start();\n\n return await offlineAudioCtx.startRendering();\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,mBAAyC;AAmIlC,IAAM,wBAAwB,CAAC,SACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,aAAa,IAAI,WAAW;AAClC,aAAW,SAAS,MAAM;AACxB,YAAQ,WAAW,MAAqB;AAAA,EAC1C;AAEA,aAAW,UAAU,MAAM;AACzB,WAAO,WAAW,KAAK;AAAA,EACzB;AAEA,aAAW,kBAAkB,IAAI;AACnC,CAAC;;;ACzII,IAAM,gBAAgB,OAAO,SAAe;AACjD,QAAM,WAAW,IAAI,aAAa;AAElC,QAAM,cAAc,MAAM,sBAAsB,IAAI;AACpD,QAAM,cAAc,MAAM,SAAS,gBAAgB,WAAW;AAC9D,MAAI,SAAS,UAAU,SAAU,OAAM,SAAS,MAAM;AACtD,SAAO;AACT;AAUO,IAAM,cAAc,OAAO,aAA0B,eAAuB;AACjF,QAAM,kBAAkB,IAAI;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY,WAAW;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,mBAAmB;AAClD,SAAO,SAAS;AAChB,SAAO,QAAQ,gBAAgB,WAAW;AAC1C,SAAO,MAAM;AAEb,SAAO,MAAM,gBAAgB,eAAe;AAC9C;;;AF/BA,IAAM,oBAAoB;AAC1B,IAAM,kCAAkC;AAExC,IAAM,2BAA2B,CAAC,eAA6B;AAC7D,QAAM,WAAW,IAAI,WAAW,WAAW,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,eAAe,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,YAAY,CAAC;AAE3D,aAAS,CAAC,IAAI,KAAK,MAAM,eAAe,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,gBAC1B,MAAM;AAAA,EAAK,EAAE,QAAQ,YAAY,iBAAiB;AAAA,EAAG,CAAC,GAAG,MACvD,YAAY,eAAe,CAAC;AAC9B,EAAE,IAAI,wBAAwB;AAEhC,eAAsB,YAAY,MAAY,YAAoB;AAChE,QAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,QAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;AAC3E,QAAM,eAAe,YAAY;AACjC,QAAM,gBAAgB,mBAAmB,WAAW;AACpD,QAAM,aAAa,IAAI,OAAO,WAAW,cAAc,YAAY,iBAAiB;AAEpF,QAAM,aAA0B,CAAC;AACjC,MAAI,YAAY,cAAc,CAAC,EAAE;AACjC,WACM,IAAI,GACR,aAAa,iCACb,KAAK,iCACL;AACA,UAAM,CAAC,kBAAkB,iBAAiB,IAAI,cAAc;AAAA,MAAI,CAAC,YAC/D,QAAQ,SAAS,GAAG,IAAI,+BAA+B;AAAA,IACzD;AACA,eAAW;AAAA,MACT,IAAI,UAAU,WAAW,aAAa,kBAAkB,iBAAiB,CAAC;AAAA,IAC5E;AACA,iBAAa;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UAAU,OAAQ,YAAW,KAAK,IAAI,UAAU,SAAS,CAAC;AAC9D,SAAO,IAAI,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClE;",
6
6
  "names": []
7
7
  }
@@ -80,9 +80,10 @@ var float32ArrayToInt16Array = (float32Arr) => {
80
80
  }
81
81
  return int16Arr;
82
82
  };
83
- var splitDataByChannel = (audioBuffer) => Array.from({ length: audioBuffer.numberOfChannels }, (_, i) => audioBuffer.getChannelData(i)).map(
84
- float32ArrayToInt16Array
85
- );
83
+ var splitDataByChannel = (audioBuffer) => Array.from(
84
+ { length: audioBuffer.numberOfChannels },
85
+ (_, i) => audioBuffer.getChannelData(i)
86
+ ).map(float32ArrayToInt16Array);
86
87
  async function encodeToMp3(file, sampleRate) {
87
88
  const lameJs = await import("@breezystack/lamejs");
88
89
  const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);
@@ -95,7 +96,9 @@ async function encodeToMp3(file, sampleRate) {
95
96
  const [leftChannelBlock, rightChannelBlock] = dataByChannel.map(
96
97
  (channel) => channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK)
97
98
  );
98
- dataBuffer.push(new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)));
99
+ dataBuffer.push(
100
+ new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock))
101
+ );
99
102
  remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;
100
103
  }
101
104
  const lastBlock = mp3Encoder.flush();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/plugins/encoders/mp3.ts", "../../../src/components/ReactFileUtilities/utils.ts", "../../../src/components/MediaRecorder/transcode/audioProcessing.ts"],
4
- "sourcesContent": ["import {\n renderAudio,\n toAudioBuffer,\n} from '../../components/MediaRecorder/transcode/audioProcessing';\n\nconst ENCODING_BIT_RATE = 128; // kbps;\nconst COUNT_SAMPLES_PER_ENCODED_BLOCK = 1152;\n\nconst float32ArrayToInt16Array = (float32Arr: Float32Array) => {\n const int16Arr = new Int16Array(float32Arr.length);\n for (let i = 0; i < float32Arr.length; i++) {\n const float32Value = float32Arr[i];\n // Clamp the float value between -1 and 1\n const clampedValue = Math.max(-1, Math.min(1, float32Value));\n // Convert the float value to a signed 16-bit integer\n int16Arr[i] = Math.round(clampedValue * 32767);\n }\n return int16Arr;\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n Array.from({ length: audioBuffer.numberOfChannels }, (_, i) => audioBuffer.getChannelData(i)).map(\n float32ArrayToInt16Array,\n );\n\nexport async function encodeToMp3(file: File, sampleRate: number) {\n const lameJs = await import('@breezystack/lamejs');\n const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n const channelCount = audioBuffer.numberOfChannels;\n const dataByChannel = splitDataByChannel(audioBuffer);\n const mp3Encoder = new lameJs.Mp3Encoder(channelCount, sampleRate, ENCODING_BIT_RATE);\n\n const dataBuffer: Int8Array[] = [];\n let remaining = dataByChannel[0].length;\n for (\n let i = 0;\n remaining >= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n i += COUNT_SAMPLES_PER_ENCODED_BLOCK\n ) {\n const [leftChannelBlock, rightChannelBlock] = dataByChannel.map((channel) =>\n channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK),\n );\n dataBuffer.push(new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)));\n remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n }\n\n const lastBlock = mp3Encoder.flush();\n if (lastBlock.length) dataBuffer.push(new Int8Array(lastBlock));\n return new Blob(dataBuffer, { type: 'audio/mp3;sbu_type=voice' });\n}\n", "import { FileLike, RecordedMediaType } from './types';\nimport { ChangeEvent, useCallback } from 'react';\n\nexport const useHandleFileChangeWrapper = (\n resetOnChange = false,\n handler?: (files: Array<File>) => void,\n) =>\n useCallback(\n ({ currentTarget }: ChangeEvent<HTMLInputElement>) => {\n const { files } = currentTarget;\n\n if (!files) return;\n\n try {\n handler?.(Array.from(files));\n } catch (error) {\n console.error(error);\n }\n\n if (resetOnChange) currentTarget.value = '';\n },\n [handler, resetOnChange],\n );\n\nexport function dataTransferItemsHaveFiles(items?: DataTransferItem[]): boolean {\n if (!items || !items.length) {\n return false;\n }\n for (const item of items) {\n if (item.kind === 'file' || item.type === 'text/html') {\n return true;\n }\n }\n return false;\n}\n\nexport async function dataTransferItemsToFiles(items?: DataTransferItem[]): Promise<FileLike[]> {\n if (!items || !items.length) {\n return [];\n }\n\n // If there are files inside the DataTransferItem prefer those\n const fileLikes = getFileLikes(items);\n if (fileLikes.length) {\n return fileLikes;\n }\n\n // Otherwise extract images from html\n const blobPromises = [];\n for (const item of items) {\n if (item.type === 'text/html') {\n blobPromises.push(\n new Promise<void>((accept) => {\n item.getAsString(async (s) => {\n const imagePromises = extractImageSources(s).map((src) =>\n getImageSource(fileLikes, src),\n );\n\n await Promise.all(imagePromises);\n accept();\n });\n }),\n );\n }\n }\n await Promise.all(blobPromises);\n return fileLikes;\n}\n\nfunction getFileLikes(items: DataTransferItem[]) {\n const fileLikes = [];\n for (const item of items) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) {\n fileLikes.push(file);\n }\n }\n }\n return fileLikes;\n}\n\nasync function getImageSource(fileLikes: FileLike[], src: string) {\n let res;\n try {\n res = await fetch(src);\n } catch (e) {\n return;\n }\n const contentType = res.headers.get('Content-type') || 'application/octet-stream';\n const buf = await res.arrayBuffer();\n const blob = new Blob([buf], { type: contentType });\n fileLikes.push(blob);\n}\n\nconst extractImageSources = (s: string) => {\n const imageTags = new DOMParser().parseFromString(s, 'text/html').getElementsByTagName('img');\n return Array.from(imageTags, (tag) => tag.src).filter((tag) => tag);\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n obj instanceof Blob && !(obj instanceof File);\n\nexport const createFileFromBlobs = ({\n blobsArray,\n fileName,\n mimeType,\n}: {\n blobsArray: Blob[];\n fileName: string;\n mimeType: string;\n}) => {\n const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n const match = mimeType.match(/\\/([^/;]+)/);\n return match && match[1];\n};\n\nexport const getRecordedMediaTypeFromMimeType = (mimeType: string): RecordedMediaType | null => {\n const match = mimeType.match(/^(audio|video)\\/.*$/);\n return match && (match[1] as RecordedMediaType);\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = () => {\n resolve(fileReader.result as ArrayBuffer);\n };\n\n fileReader.onerror = () => {\n reject(fileReader.error);\n };\n\n fileReader.readAsArrayBuffer(file);\n });\n\nexport const generateFileName = (mimeType: string) =>\n `file_${new Date().toISOString()}.${getExtensionFromMimeType(mimeType)}`;\n", "import { readFileAsArrayBuffer } from '../../ReactFileUtilities';\n\n/**\n * In the context of resampling audio data, AudioContext is used to decode the input audio file into an AudioBuffer,\n * which is a fundamental data structure representing audio data.\n * @param file\n */\nexport const toAudioBuffer = async (file: File) => {\n const audioCtx = new AudioContext();\n\n const arrayBuffer = await readFileAsArrayBuffer(file);\n const decodedData = await audioCtx.decodeAudioData(arrayBuffer);\n if (audioCtx.state !== 'closed') await audioCtx.close();\n return decodedData;\n};\n\n/**\n * OfflineAudioContext is a specialized type of AudioContext that does not render audio in real-time and is used for offline audio processing tasks.\n * It allows performing audio processing and rendering without actually playing the audio through speakers or outputting it to a destination.\n * In the context of resampling audio data, OfflineAudioContext is used to resample the decoded AudioBuffer from a file to the desired sample rate.\n * It provides more flexibility and control over audio processing, as it can operate at different sample rates and durations compared to real-time audio contexts.\n * @param audioBuffer\n * @param sampleRate\n */\nexport const renderAudio = async (audioBuffer: AudioBuffer, sampleRate: number) => {\n const offlineAudioCtx = new OfflineAudioContext(\n audioBuffer.numberOfChannels,\n audioBuffer.duration * sampleRate,\n sampleRate,\n );\n const source = offlineAudioCtx.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(offlineAudioCtx.destination);\n source.start();\n\n return await offlineAudioCtx.startRendering();\n};\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,mBAAyC;AA6HlC,IAAM,wBAAwB,CAAC,SACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,aAAa,IAAI,WAAW;AAClC,aAAW,SAAS,MAAM;AACxB,YAAQ,WAAW,MAAqB;AAAA,EAC1C;AAEA,aAAW,UAAU,MAAM;AACzB,WAAO,WAAW,KAAK;AAAA,EACzB;AAEA,aAAW,kBAAkB,IAAI;AACnC,CAAC;;;ACnII,IAAM,gBAAgB,OAAO,SAAe;AACjD,QAAM,WAAW,IAAI,aAAa;AAElC,QAAM,cAAc,MAAM,sBAAsB,IAAI;AACpD,QAAM,cAAc,MAAM,SAAS,gBAAgB,WAAW;AAC9D,MAAI,SAAS,UAAU,SAAU,OAAM,SAAS,MAAM;AACtD,SAAO;AACT;AAUO,IAAM,cAAc,OAAO,aAA0B,eAAuB;AACjF,QAAM,kBAAkB,IAAI;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY,WAAW;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,mBAAmB;AAClD,SAAO,SAAS;AAChB,SAAO,QAAQ,gBAAgB,WAAW;AAC1C,SAAO,MAAM;AAEb,SAAO,MAAM,gBAAgB,eAAe;AAC9C;;;AF/BA,IAAM,oBAAoB;AAC1B,IAAM,kCAAkC;AAExC,IAAM,2BAA2B,CAAC,eAA6B;AAC7D,QAAM,WAAW,IAAI,WAAW,WAAW,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,eAAe,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,YAAY,CAAC;AAE3D,aAAS,CAAC,IAAI,KAAK,MAAM,eAAe,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,gBAC1B,MAAM,KAAK,EAAE,QAAQ,YAAY,iBAAiB,GAAG,CAAC,GAAG,MAAM,YAAY,eAAe,CAAC,CAAC,EAAE;AAAA,EAC5F;AACF;AAEF,eAAsB,YAAY,MAAY,YAAoB;AAChE,QAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,QAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;AAC3E,QAAM,eAAe,YAAY;AACjC,QAAM,gBAAgB,mBAAmB,WAAW;AACpD,QAAM,aAAa,IAAI,OAAO,WAAW,cAAc,YAAY,iBAAiB;AAEpF,QAAM,aAA0B,CAAC;AACjC,MAAI,YAAY,cAAc,CAAC,EAAE;AACjC,WACM,IAAI,GACR,aAAa,iCACb,KAAK,iCACL;AACA,UAAM,CAAC,kBAAkB,iBAAiB,IAAI,cAAc;AAAA,MAAI,CAAC,YAC/D,QAAQ,SAAS,GAAG,IAAI,+BAA+B;AAAA,IACzD;AACA,eAAW,KAAK,IAAI,UAAU,WAAW,aAAa,kBAAkB,iBAAiB,CAAC,CAAC;AAC3F,iBAAa;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UAAU,OAAQ,YAAW,KAAK,IAAI,UAAU,SAAS,CAAC;AAC9D,SAAO,IAAI,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClE;",
4
+ "sourcesContent": ["import {\n renderAudio,\n toAudioBuffer,\n} from '../../components/MediaRecorder/transcode/audioProcessing';\n\nconst ENCODING_BIT_RATE = 128; // kbps;\nconst COUNT_SAMPLES_PER_ENCODED_BLOCK = 1152;\n\nconst float32ArrayToInt16Array = (float32Arr: Float32Array) => {\n const int16Arr = new Int16Array(float32Arr.length);\n for (let i = 0; i < float32Arr.length; i++) {\n const float32Value = float32Arr[i];\n // Clamp the float value between -1 and 1\n const clampedValue = Math.max(-1, Math.min(1, float32Value));\n // Convert the float value to a signed 16-bit integer\n int16Arr[i] = Math.round(clampedValue * 32767);\n }\n return int16Arr;\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n Array.from({ length: audioBuffer.numberOfChannels }, (_, i) =>\n audioBuffer.getChannelData(i),\n ).map(float32ArrayToInt16Array);\n\nexport async function encodeToMp3(file: File, sampleRate: number) {\n const lameJs = await import('@breezystack/lamejs');\n const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n const channelCount = audioBuffer.numberOfChannels;\n const dataByChannel = splitDataByChannel(audioBuffer);\n const mp3Encoder = new lameJs.Mp3Encoder(channelCount, sampleRate, ENCODING_BIT_RATE);\n\n const dataBuffer: Int8Array[] = [];\n let remaining = dataByChannel[0].length;\n for (\n let i = 0;\n remaining >= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n i += COUNT_SAMPLES_PER_ENCODED_BLOCK\n ) {\n const [leftChannelBlock, rightChannelBlock] = dataByChannel.map((channel) =>\n channel.subarray(i, i + COUNT_SAMPLES_PER_ENCODED_BLOCK),\n );\n dataBuffer.push(\n new Int8Array(mp3Encoder.encodeBuffer(leftChannelBlock, rightChannelBlock)),\n );\n remaining -= COUNT_SAMPLES_PER_ENCODED_BLOCK;\n }\n\n const lastBlock = mp3Encoder.flush();\n if (lastBlock.length) dataBuffer.push(new Int8Array(lastBlock));\n return new Blob(dataBuffer, { type: 'audio/mp3;sbu_type=voice' });\n}\n", "import { FileLike, RecordedMediaType } from './types';\nimport { ChangeEvent, useCallback } from 'react';\n\nexport const useHandleFileChangeWrapper = (\n resetOnChange = false,\n handler?: (files: Array<File>) => void,\n) =>\n useCallback(\n ({ currentTarget }: ChangeEvent<HTMLInputElement>) => {\n const { files } = currentTarget;\n\n if (!files) return;\n\n try {\n handler?.(Array.from(files));\n } catch (error) {\n console.error(error);\n }\n\n if (resetOnChange) currentTarget.value = '';\n },\n [handler, resetOnChange],\n );\n\nexport function dataTransferItemsHaveFiles(items?: DataTransferItem[]): boolean {\n if (!items || !items.length) {\n return false;\n }\n for (const item of items) {\n if (item.kind === 'file' || item.type === 'text/html') {\n return true;\n }\n }\n return false;\n}\n\nexport async function dataTransferItemsToFiles(\n items?: DataTransferItem[],\n): Promise<FileLike[]> {\n if (!items || !items.length) {\n return [];\n }\n\n // If there are files inside the DataTransferItem prefer those\n const fileLikes = getFileLikes(items);\n if (fileLikes.length) {\n return fileLikes;\n }\n\n // Otherwise extract images from html\n const blobPromises = [];\n for (const item of items) {\n if (item.type === 'text/html') {\n blobPromises.push(\n new Promise<void>((accept) => {\n item.getAsString(async (s) => {\n const imagePromises = extractImageSources(s).map((src) =>\n getImageSource(fileLikes, src),\n );\n\n await Promise.all(imagePromises);\n accept();\n });\n }),\n );\n }\n }\n await Promise.all(blobPromises);\n return fileLikes;\n}\n\nfunction getFileLikes(items: DataTransferItem[]) {\n const fileLikes = [];\n for (const item of items) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) {\n fileLikes.push(file);\n }\n }\n }\n return fileLikes;\n}\n\nasync function getImageSource(fileLikes: FileLike[], src: string) {\n let res;\n try {\n res = await fetch(src);\n } catch (e) {\n return;\n }\n const contentType = res.headers.get('Content-type') || 'application/octet-stream';\n const buf = await res.arrayBuffer();\n const blob = new Blob([buf], { type: contentType });\n fileLikes.push(blob);\n}\n\nconst extractImageSources = (s: string) => {\n const imageTags = new DOMParser()\n .parseFromString(s, 'text/html')\n .getElementsByTagName('img');\n return Array.from(imageTags, (tag) => tag.src).filter((tag) => tag);\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n obj instanceof Blob && !(obj instanceof File);\n\nexport const createFileFromBlobs = ({\n blobsArray,\n fileName,\n mimeType,\n}: {\n blobsArray: Blob[];\n fileName: string;\n mimeType: string;\n}) => {\n const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n const match = mimeType.match(/\\/([^/;]+)/);\n return match && match[1];\n};\n\nexport const getRecordedMediaTypeFromMimeType = (\n mimeType: string,\n): RecordedMediaType | null => {\n const match = mimeType.match(/^(audio|video)\\/.*$/);\n return match && (match[1] as RecordedMediaType);\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = () => {\n resolve(fileReader.result as ArrayBuffer);\n };\n\n fileReader.onerror = () => {\n reject(fileReader.error);\n };\n\n fileReader.readAsArrayBuffer(file);\n });\n\nexport const generateFileName = (mimeType: string) =>\n `file_${new Date().toISOString()}.${getExtensionFromMimeType(mimeType)}`;\n", "import { readFileAsArrayBuffer } from '../../ReactFileUtilities';\n\n/**\n * In the context of resampling audio data, AudioContext is used to decode the input audio file into an AudioBuffer,\n * which is a fundamental data structure representing audio data.\n * @param file\n */\nexport const toAudioBuffer = async (file: File) => {\n const audioCtx = new AudioContext();\n\n const arrayBuffer = await readFileAsArrayBuffer(file);\n const decodedData = await audioCtx.decodeAudioData(arrayBuffer);\n if (audioCtx.state !== 'closed') await audioCtx.close();\n return decodedData;\n};\n\n/**\n * OfflineAudioContext is a specialized type of AudioContext that does not render audio in real-time and is used for offline audio processing tasks.\n * It allows performing audio processing and rendering without actually playing the audio through speakers or outputting it to a destination.\n * In the context of resampling audio data, OfflineAudioContext is used to resample the decoded AudioBuffer from a file to the desired sample rate.\n * It provides more flexibility and control over audio processing, as it can operate at different sample rates and durations compared to real-time audio contexts.\n * @param audioBuffer\n * @param sampleRate\n */\nexport const renderAudio = async (audioBuffer: AudioBuffer, sampleRate: number) => {\n const offlineAudioCtx = new OfflineAudioContext(\n audioBuffer.numberOfChannels,\n audioBuffer.duration * sampleRate,\n sampleRate,\n );\n const source = offlineAudioCtx.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(offlineAudioCtx.destination);\n source.start();\n\n return await offlineAudioCtx.startRendering();\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,mBAAyC;AAmIlC,IAAM,wBAAwB,CAAC,SACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,QAAM,aAAa,IAAI,WAAW;AAClC,aAAW,SAAS,MAAM;AACxB,YAAQ,WAAW,MAAqB;AAAA,EAC1C;AAEA,aAAW,UAAU,MAAM;AACzB,WAAO,WAAW,KAAK;AAAA,EACzB;AAEA,aAAW,kBAAkB,IAAI;AACnC,CAAC;;;ACzII,IAAM,gBAAgB,OAAO,SAAe;AACjD,QAAM,WAAW,IAAI,aAAa;AAElC,QAAM,cAAc,MAAM,sBAAsB,IAAI;AACpD,QAAM,cAAc,MAAM,SAAS,gBAAgB,WAAW;AAC9D,MAAI,SAAS,UAAU,SAAU,OAAM,SAAS,MAAM;AACtD,SAAO;AACT;AAUO,IAAM,cAAc,OAAO,aAA0B,eAAuB;AACjF,QAAM,kBAAkB,IAAI;AAAA,IAC1B,YAAY;AAAA,IACZ,YAAY,WAAW;AAAA,IACvB;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,mBAAmB;AAClD,SAAO,SAAS;AAChB,SAAO,QAAQ,gBAAgB,WAAW;AAC1C,SAAO,MAAM;AAEb,SAAO,MAAM,gBAAgB,eAAe;AAC9C;;;AF/BA,IAAM,oBAAoB;AAC1B,IAAM,kCAAkC;AAExC,IAAM,2BAA2B,CAAC,eAA6B;AAC7D,QAAM,WAAW,IAAI,WAAW,WAAW,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,eAAe,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,YAAY,CAAC;AAE3D,aAAS,CAAC,IAAI,KAAK,MAAM,eAAe,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,gBAC1B,MAAM;AAAA,EAAK,EAAE,QAAQ,YAAY,iBAAiB;AAAA,EAAG,CAAC,GAAG,MACvD,YAAY,eAAe,CAAC;AAC9B,EAAE,IAAI,wBAAwB;AAEhC,eAAsB,YAAY,MAAY,YAAoB;AAChE,QAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,QAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;AAC3E,QAAM,eAAe,YAAY;AACjC,QAAM,gBAAgB,mBAAmB,WAAW;AACpD,QAAM,aAAa,IAAI,OAAO,WAAW,cAAc,YAAY,iBAAiB;AAEpF,QAAM,aAA0B,CAAC;AACjC,MAAI,YAAY,cAAc,CAAC,EAAE;AACjC,WACM,IAAI,GACR,aAAa,iCACb,KAAK,iCACL;AACA,UAAM,CAAC,kBAAkB,iBAAiB,IAAI,cAAc;AAAA,MAAI,CAAC,YAC/D,QAAQ,SAAS,GAAG,IAAI,+BAA+B;AAAA,IACzD;AACA,eAAW;AAAA,MACT,IAAI,UAAU,WAAW,aAAa,kBAAkB,iBAAiB,CAAC;AAAA,IAC5E;AACA,iBAAa;AAAA,EACf;AAEA,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,UAAU,OAAQ,YAAW,KAAK,IAAI,UAAU,SAAS,CAAC;AAC9D,SAAO,IAAI,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClE;",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@
7
7
  flex-direction: column;
8
8
  justify-content: center;
9
9
 
10
+ &.str-chat__channel-search--active.str-chat__channel-search--inline,
10
11
  &.str-chat__channel-search--with-results.str-chat__channel-search--inline {
11
12
  height: 100%;
12
13
  }
@@ -23,6 +23,9 @@
23
23
  var(--str-chat__quoted-message-inside-message-input-max-width) +
24
24
  calc(var(--str-chat__spacing-px) * 50)
25
25
  );
26
+
27
+ /* The maximum number of lines displayed for quoted messages, set to "none" to turn off clamping */
28
+ --str-chat__quoted-message-line-clamp: 5;
26
29
  }
27
30
 
28
31
  .str-chat__message {
@@ -59,12 +62,21 @@
59
62
  }
60
63
  }
61
64
 
65
+ .str-chat__quoted-message-text-value {
66
+ overflow: hidden;
67
+ display: -webkit-box;
68
+ -webkit-line-clamp: var(--str-chat__quoted-message-line-clamp);
69
+ line-clamp: var(--str-chat__quoted-message-line-clamp);
70
+ -webkit-box-orient: vertical;
71
+ }
72
+
62
73
  .str-chat__message,
63
74
  .str-chat__quoted-message-preview {
64
75
  @mixin chat-bubble-spacing {
65
76
  padding: var(--str-chat__spacing-2) var(--str-chat__spacing-4);
66
77
 
67
78
  p {
79
+ white-space: pre-line;
68
80
  margin: 0;
69
81
  }
70
82
  }
@@ -165,10 +177,6 @@
165
177
  .str-chat__message-text-inner {
166
178
  @include utils.prevent-glitch-text-overflow;
167
179
  }
168
-
169
- p {
170
- white-space: pre-line;
171
- }
172
180
  }
173
181
  }
174
182
  }
@@ -357,7 +365,6 @@
357
365
  }
358
366
  }
359
367
 
360
-
361
368
  .str-chat__message-inner {
362
369
  .str-chat__message-options {
363
370
  display: none;
@@ -332,8 +332,8 @@
332
332
  }
333
333
 
334
334
  .str-chat__poll-creation-dialog {
335
+ height: 100%;
335
336
  width: 100%;
336
- height: 700px;
337
337
  display: flex;
338
338
  flex-direction: column;
339
339
 
@@ -0,0 +1,148 @@
1
+ @use '../utils';
2
+
3
+ .str-chat__search {
4
+ position: relative;
5
+ display: flex;
6
+ flex-direction: column;
7
+ justify-content: center;
8
+
9
+ &.str-chat__search--active {
10
+ flex: 1;
11
+ max-height: 100%;
12
+ }
13
+
14
+ .str-chat__search-bar {
15
+ @include utils.flex-row-center;
16
+ padding: var(--str-chat__spacing-2_5) var(--str-chat__spacing-2);
17
+ gap: 0.25rem;
18
+
19
+ .str-chat__search-bar-button {
20
+ @include utils.button-reset;
21
+ padding: var(--str-chat__spacing-1);
22
+ cursor: pointer;
23
+ }
24
+
25
+ .str-chat__search-input--wrapper {
26
+ display: flex;
27
+ align-items: center;
28
+ flex: 1;
29
+ padding: var(--str-chat__spacing-1_5) var(--str-chat__spacing-2);
30
+ min-width: 0;
31
+
32
+ .str-chat__search-input--icon {
33
+ height: 20px;
34
+ width: 20px;
35
+ margin-right: 0.5rem;
36
+ }
37
+
38
+ .str-chat__search-input--clear-button {
39
+ @include utils.button-reset;
40
+ cursor: pointer;
41
+ padding: 0;
42
+
43
+ &:disabled {
44
+ cursor: default;
45
+ }
46
+
47
+ .str-chat__search-input--clear-button-icon {
48
+ height: 20px;
49
+ width: 20px;
50
+ mask-size: 20px;
51
+ -webkit-mask-size: 20px;
52
+ }
53
+ }
54
+
55
+ input {
56
+ flex: 1;
57
+ min-width: 0;
58
+ }
59
+ }
60
+ }
61
+
62
+ .str-chat__search-results {
63
+ flex: 1;
64
+ display: flex;
65
+ flex-direction: column;
66
+ min-height: 0;
67
+
68
+ .str-chat__search-results-header {
69
+ width: 100%;
70
+
71
+ button {
72
+ @include utils.button-reset();
73
+ cursor: pointer;
74
+ }
75
+
76
+ .str-chat__search-results-header__filter-source-buttons {
77
+ display: flex;
78
+ flex-wrap: wrap;
79
+ gap: 0.5rem;
80
+ padding: var(--str-chat__spacing-3) var(--str-chat__spacing-2_5);
81
+ width: 100%;
82
+
83
+ .str-chat__search-results-header__filter-source-button {
84
+ padding: 0.5rem 0.75rem;
85
+ border-radius: var(--str-chat__border-radius-circle);
86
+ background-color: var(--str-chat__tertiary-surface-color);
87
+ }
88
+
89
+ .str-chat__search-results-header__filter-source-button--active {
90
+ background-color: var(--str-chat__surface-color);
91
+ color: var(--str-chat__text-color);
92
+ font-weight: 500;
93
+ }
94
+ }
95
+ }
96
+
97
+ .str-chat__search-results-presearch,
98
+ .str-chat__search-source-results-empty {
99
+ width: 100%;
100
+ display: flex;
101
+ justify-content: center;
102
+ align-items: center;
103
+ padding: 1.25rem;
104
+ }
105
+
106
+ .str-chat__search-source-results {
107
+ flex: 1;
108
+ display: flex;
109
+ flex-direction: column;
110
+ min-height: 0;
111
+
112
+ .str-chat__search-source-result-list {
113
+ flex: 1;
114
+ display: flex;
115
+ flex-direction: column;
116
+ min-height: 0;
117
+
118
+ .str-chat__infinite-scroll-paginator__content {
119
+ display: flex;
120
+ flex-direction: column;
121
+ }
122
+
123
+ .str-chat__search-result {
124
+ display: flex;
125
+ align-items: center;
126
+ width: 100%;
127
+ column-gap: var(--str-chat__spacing-2);
128
+ padding: var(--str-chat__spacing-3) var(--str-chat__spacing-2);
129
+
130
+ .search__result-text,
131
+ .str-chat__search-result--display-name {
132
+ @include utils.ellipsis-text;
133
+ @include utils.prevent-glitch-text-overflow;
134
+ }
135
+ }
136
+
137
+ .str-chat__search-source-result-list__footer {
138
+ height: 4rem;
139
+ width: 100%;
140
+ display: flex;
141
+ justify-content: center;
142
+ align-items: center;
143
+ flex-direction: column;
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }