diff --git a/apps/meteor/client/views/room/composer/ComposerBoxPopup.tsx b/apps/meteor/client/components/AutocompletePopup/ComposerBoxPopup.tsx similarity index 100% rename from apps/meteor/client/views/room/composer/ComposerBoxPopup.tsx rename to apps/meteor/client/components/AutocompletePopup/ComposerBoxPopup.tsx diff --git a/apps/meteor/client/components/AutocompletePopup/ComposerPopupOption.ts b/apps/meteor/client/components/AutocompletePopup/ComposerPopupOption.ts new file mode 100644 index 0000000000000..0d4050abeeecd --- /dev/null +++ b/apps/meteor/client/components/AutocompletePopup/ComposerPopupOption.ts @@ -0,0 +1,39 @@ +import type { Optional } from '@rocket.chat/core-typings'; +import type { ReactNode } from 'react'; + +export type ComposerPopupOption = { + title?: string; + getItemsFromLocal?: (filter: any) => Promise; + getItemsFromServer?: (filter: any) => Promise; + blurOnSelectItem?: boolean; + closeOnEsc?: boolean; + + trigger?: string; + triggerAnywhere?: boolean; + triggerLength?: number; + + suffix?: string; + prefix?: string; + + matchSelectorRegex?: RegExp; + preview?: boolean; + + getValue: (item: T) => string; + + renderItem?: ({ item }: { item: T }) => ReactNode; + disabled?: boolean; +}; + +export const createMessageBoxPopupConfig = ( + partial: Optional, 'getValue'>, +): ComposerPopupOption => { + return { + blurOnSelectItem: true, + closeOnEsc: true, + triggerAnywhere: true, + suffix: ' ', + prefix: partial.prefix ?? partial.trigger ?? ' ', + getValue: (item) => item._id, + ...partial, + }; +}; diff --git a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopup.ts b/apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopup.ts similarity index 98% rename from apps/meteor/client/views/room/composer/hooks/useComposerBoxPopup.ts rename to apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopup.ts index 16889f6ad0b58..b6af8add695b8 100644 --- a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopup.ts +++ b/apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopup.ts @@ -4,8 +4,8 @@ import type { MutableRefObject } from 'react'; import { useEffect, useCallback, useState, useRef } from 'react'; import { useComposerBoxPopupQueries } from './useComposerBoxPopupQueries'; -import { useChat } from '../../contexts/ChatContext'; -import type { ComposerPopupOption } from '../../contexts/ComposerPopupContext'; +import { useChat } from '../../../views/room/contexts/ChatContext'; +import type { ComposerPopupOption } from '../ComposerPopupOption'; type ComposerBoxPopupImperativeCommands = MutableRefObject< | { diff --git a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts b/apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopupQueries.ts similarity index 90% rename from apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts rename to apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopupQueries.ts index 76a68f14d85b1..318e2e9bd5b22 100644 --- a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts +++ b/apps/meteor/client/components/AutocompletePopup/hooks/useComposerBoxPopupQueries.ts @@ -3,8 +3,8 @@ import { keepPreviousData, useQueries } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; import { useEnablePopupPreview } from './useEnablePopupPreview'; -import { slashCommands } from '../../../../../app/utils/client/slashCommand'; -import type { ComposerPopupOption } from '../../contexts/ComposerPopupContext'; +import { slashCommands } from '../../../../app/utils/client/slashCommand'; +import type { ComposerPopupOption } from '../ComposerPopupOption'; export const useComposerBoxPopupQueries = (filter: unknown, popup?: ComposerPopupOption) => { const [counter, setCounter] = useState(0); diff --git a/apps/meteor/client/views/room/composer/hooks/useEnablePopupPreview.ts b/apps/meteor/client/components/AutocompletePopup/hooks/useEnablePopupPreview.ts similarity index 76% rename from apps/meteor/client/views/room/composer/hooks/useEnablePopupPreview.ts rename to apps/meteor/client/components/AutocompletePopup/hooks/useEnablePopupPreview.ts index d8afeba55191c..a9d391fadd287 100644 --- a/apps/meteor/client/views/room/composer/hooks/useEnablePopupPreview.ts +++ b/apps/meteor/client/components/AutocompletePopup/hooks/useEnablePopupPreview.ts @@ -1,4 +1,4 @@ -import type { ComposerPopupOption } from '../../contexts/ComposerPopupContext'; +import type { ComposerPopupOption } from '../ComposerPopupOption'; export const useEnablePopupPreview = (filter: unknown, popup?: ComposerPopupOption) => popup && !popup.preview && (popup?.triggerLength ? typeof filter === 'string' && popup.triggerLength - 1 < filter.length : true); diff --git a/apps/meteor/client/views/room/composer/ComposerBoxPopupPreview.tsx b/apps/meteor/client/views/room/composer/ComposerBoxPopupPreview.tsx index dfa02a7829945..7762877cdd965 100644 --- a/apps/meteor/client/views/room/composer/ComposerBoxPopupPreview.tsx +++ b/apps/meteor/client/views/room/composer/ComposerBoxPopupPreview.tsx @@ -4,7 +4,7 @@ import { useEndpoint } from '@rocket.chat/ui-contexts'; import type { ForwardedRef, ReactNode } from 'react'; import { forwardRef, useEffect, useId, useImperativeHandle } from 'react'; -import type { ComposerBoxPopupProps } from './ComposerBoxPopup'; +import type { ComposerBoxPopupProps } from '../../../components/AutocompletePopup/ComposerBoxPopup'; import { useChat } from '../contexts/ChatContext'; type ComposerBoxPopupPreviewItem = { _id: string; type: 'image' | 'video' | 'audio' | 'text' | 'other'; value: string; sort?: number }; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx index ca2baa22c1b7b..741325c4498af 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx @@ -21,11 +21,17 @@ import MessageBoxFormattingToolbar from './MessageBoxFormattingToolbar'; import MessageBoxHint from './MessageBoxHint'; import MessageBoxReplies from './MessageBoxReplies'; import MessageComposerFiles from './MessageComposerFiles'; +import { useDraft } from './hooks/useDraft'; +import { useMessageBoxAutoFocus } from './hooks/useMessageBoxAutoFocus'; +import { useMessageBoxPlaceholder } from './hooks/useMessageBoxPlaceholder'; import { handleSelectionWrapping } from './wrapSelection'; import { createComposerAPI } from '../../../../../app/ui-message/client/messageBox/createComposerAPI'; import type { FormattingButton } from '../../../../../app/ui-message/client/messageBox/messageBoxFormatting'; import { formattingButtons } from '../../../../../app/ui-message/client/messageBox/messageBoxFormatting'; import { getImageExtensionFromMime } from '../../../../../lib/getImageExtensionFromMime'; +import ComposerBoxPopup from '../../../../components/AutocompletePopup/ComposerBoxPopup'; +import { useComposerBoxPopup } from '../../../../components/AutocompletePopup/hooks/useComposerBoxPopup'; +import { useEnablePopupPreview } from '../../../../components/AutocompletePopup/hooks/useEnablePopupPreview'; import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime'; import { useIsFederationEnabled } from '../../../../hooks/useIsFederationEnabled'; import type { ComposerAPI } from '../../../../lib/chats/ChatAPI'; @@ -38,16 +44,10 @@ import { useFileUpload } from '../../body/hooks/useFileUpload'; import { useChat } from '../../contexts/ChatContext'; import { useComposerPopupOptions } from '../../contexts/ComposerPopupContext'; import { useRoom, useRoomSubscription } from '../../contexts/RoomContext'; -import ComposerBoxPopup from '../ComposerBoxPopup'; import ComposerBoxPopupPreview from '../ComposerBoxPopupPreview'; import ComposerUserActionIndicator from '../ComposerUserActionIndicator'; import { useAutoGrow } from '../RoomComposer/hooks/useAutoGrow'; -import { useComposerBoxPopup } from '../hooks/useComposerBoxPopup'; -import { useEnablePopupPreview } from '../hooks/useEnablePopupPreview'; import { useMessageComposerMergedRefs } from '../hooks/useMessageComposerMergedRefs'; -import { useDraft } from './hooks/useDraft'; -import { useMessageBoxAutoFocus } from './hooks/useMessageBoxAutoFocus'; -import { useMessageBoxPlaceholder } from './hooks/useMessageBoxPlaceholder'; const reducer = (_: unknown, event: FormEvent): boolean => { const target = event.target as HTMLInputElement; diff --git a/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts b/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts index 3ea2b4b218101..0bc554bb5304e 100644 --- a/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts +++ b/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts @@ -1,48 +1,11 @@ -import type { Optional } from '@rocket.chat/core-typings'; -import type { ReactNode } from 'react'; import { useContext, createContext } from 'react'; -export type ComposerPopupOption = { - title?: string; - getItemsFromLocal?: (filter: any) => Promise; - getItemsFromServer?: (filter: any) => Promise; - blurOnSelectItem?: boolean; - closeOnEsc?: boolean; - - trigger?: string; - triggerAnywhere?: boolean; - triggerLength?: number; - - suffix?: string; - prefix?: string; - - matchSelectorRegex?: RegExp; - preview?: boolean; - - getValue: (item: T) => string; - - renderItem?: ({ item }: { item: T }) => ReactNode; - disabled?: boolean; -}; +import type { ComposerPopupOption } from '../../../components/AutocompletePopup/ComposerPopupOption'; export type ComposerPopupContextValue = ComposerPopupOption[]; export const ComposerPopupContext = createContext(undefined); -export const createMessageBoxPopupConfig = ( - partial: Optional, 'getValue'>, -): ComposerPopupOption => { - return { - blurOnSelectItem: true, - closeOnEsc: true, - triggerAnywhere: true, - suffix: ' ', - prefix: partial.prefix ?? partial.trigger ?? ' ', - getValue: (item) => item._id, - ...partial, - }; -}; - export const useComposerPopupOptions = () => { const composerPopupContext = useContext(ComposerPopupContext); if (!composerPopupContext) { diff --git a/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx b/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx index 7d9a6736fbcb6..bedf8ab97ad06 100644 --- a/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx +++ b/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx @@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next'; import { hasAtLeastOnePermission } from '../../../../app/authorization/client'; import { emoji } from '../../../../app/emoji/client'; import { slashCommands } from '../../../../app/utils/client'; +import { createMessageBoxPopupConfig } from '../../../components/AutocompletePopup/ComposerPopupOption'; import { cannedResponsesQueryKeys } from '../../../lib/queryKeys'; import { Messages, Subscriptions } from '../../../stores'; import ComposerBoxPopupCannedResponse from '../composer/ComposerBoxPopupCannedResponse'; @@ -24,7 +25,7 @@ import ComposerBoxPopupSlashCommand from '../composer/ComposerBoxPopupSlashComma import ComposerBoxPopupUser from '../composer/ComposerBoxPopupUser'; import type { ComposerBoxPopupUserProps } from '../composer/ComposerBoxPopupUser'; import type { ComposerPopupContextValue } from '../contexts/ComposerPopupContext'; -import { ComposerPopupContext, createMessageBoxPopupConfig } from '../contexts/ComposerPopupContext'; +import { ComposerPopupContext } from '../contexts/ComposerPopupContext'; import useCannedResponsesQuery from './hooks/useCannedResponsesQuery'; import { normalizeUsername } from '../../../../lib/utils/normalizeUsername'; import { pipe } from '../../../lib/cachedStores/pipe';