|
|
|
|
@ -2,7 +2,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; |
|
|
|
|
import { isOmnichannelRoom } from '@rocket.chat/core-typings'; |
|
|
|
|
import { useLocalStorage } from '@rocket.chat/fuselage-hooks'; |
|
|
|
|
import { escapeRegExp } from '@rocket.chat/string-helpers'; |
|
|
|
|
import { useMethod, useSetting, useTranslation } from '@rocket.chat/ui-contexts'; |
|
|
|
|
import { useMethod, useSetting, useTranslation, useUserPreference } from '@rocket.chat/ui-contexts'; |
|
|
|
|
import React, { useMemo } from 'react'; |
|
|
|
|
import type { ReactNode } from 'react'; |
|
|
|
|
|
|
|
|
|
@ -31,7 +31,7 @@ const ComposerPopupProvider = ({ children, room }: { children: ReactNode; room: |
|
|
|
|
const cannedResponseEnabled = useSetting<boolean>('Canned_Responses_Enable'); |
|
|
|
|
const [recentEmojis] = useLocalStorage('emoji.recent', []); |
|
|
|
|
const isOmnichannel = isOmnichannelRoom(room); |
|
|
|
|
|
|
|
|
|
const useEmoji = useUserPreference('useEmojis'); |
|
|
|
|
const t = useTranslation(); |
|
|
|
|
|
|
|
|
|
const call = useMethod('getSlashCommandPreviews'); |
|
|
|
|
@ -150,63 +150,64 @@ const ComposerPopupProvider = ({ children, room }: { children: ReactNode; room: |
|
|
|
|
getValue: (item) => `${item.name || item.fname}`, |
|
|
|
|
renderItem: ({ item }) => <ComposerBoxPopupRoom {...item} />, |
|
|
|
|
}) as any, |
|
|
|
|
createMessageBoxPopupConfig<ComposerBoxPopupEmojiProps>({ |
|
|
|
|
trigger: ':', |
|
|
|
|
title: t('Emoji'), |
|
|
|
|
getItemsFromLocal: async (filter: string) => { |
|
|
|
|
const exactFinalTone = new RegExp('^tone[1-5]:*$'); |
|
|
|
|
const colorBlind = new RegExp('tone[1-5]:*$'); |
|
|
|
|
const seeColor = new RegExp('_t(?:o|$)(?:n|$)(?:e|$)(?:[1-5]|$)(?::|$)$'); |
|
|
|
|
useEmoji && |
|
|
|
|
createMessageBoxPopupConfig<ComposerBoxPopupEmojiProps>({ |
|
|
|
|
trigger: ':', |
|
|
|
|
title: t('Emoji'), |
|
|
|
|
getItemsFromLocal: async (filter: string) => { |
|
|
|
|
const exactFinalTone = new RegExp('^tone[1-5]:*$'); |
|
|
|
|
const colorBlind = new RegExp('tone[1-5]:*$'); |
|
|
|
|
const seeColor = new RegExp('_t(?:o|$)(?:n|$)(?:e|$)(?:[1-5]|$)(?::|$)$'); |
|
|
|
|
|
|
|
|
|
const emojiSort = (recents: string[]) => (a: { _id: string }, b: { _id: string }) => { |
|
|
|
|
const aExact = a._id === key ? 2 : 0; |
|
|
|
|
const bExact = b._id === key ? 2 : 0; |
|
|
|
|
const aPartial = a._id.startsWith(key) ? 1 : 0; |
|
|
|
|
const bPartial = b._id.startsWith(key) ? 1 : 0; |
|
|
|
|
const emojiSort = (recents: string[]) => (a: { _id: string }, b: { _id: string }) => { |
|
|
|
|
const aExact = a._id === key ? 2 : 0; |
|
|
|
|
const bExact = b._id === key ? 2 : 0; |
|
|
|
|
const aPartial = a._id.startsWith(key) ? 1 : 0; |
|
|
|
|
const bPartial = b._id.startsWith(key) ? 1 : 0; |
|
|
|
|
|
|
|
|
|
let aScore = aExact + aPartial; |
|
|
|
|
let bScore = bExact + bPartial; |
|
|
|
|
let aScore = aExact + aPartial; |
|
|
|
|
let bScore = bExact + bPartial; |
|
|
|
|
|
|
|
|
|
if (recents.includes(a._id)) { |
|
|
|
|
aScore += recents.indexOf(a._id) + 1; |
|
|
|
|
} |
|
|
|
|
if (recents.includes(b._id)) { |
|
|
|
|
bScore += recents.indexOf(b._id) + 1; |
|
|
|
|
} |
|
|
|
|
if (recents.includes(a._id)) { |
|
|
|
|
aScore += recents.indexOf(a._id) + 1; |
|
|
|
|
} |
|
|
|
|
if (recents.includes(b._id)) { |
|
|
|
|
bScore += recents.indexOf(b._id) + 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (aScore > bScore) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (aScore < bScore) { |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
}; |
|
|
|
|
const filterRegex = new RegExp(escapeRegExp(filter), 'i'); |
|
|
|
|
const key = `:${filter}`; |
|
|
|
|
if (aScore > bScore) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (aScore < bScore) { |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
}; |
|
|
|
|
const filterRegex = new RegExp(escapeRegExp(filter), 'i'); |
|
|
|
|
const key = `:${filter}`; |
|
|
|
|
|
|
|
|
|
const recents = recentEmojis.map((item) => `:${item}:`); |
|
|
|
|
const recents = recentEmojis.map((item) => `:${item}:`); |
|
|
|
|
|
|
|
|
|
const collection = emoji.list; |
|
|
|
|
const collection = emoji.list; |
|
|
|
|
|
|
|
|
|
return Object.keys(collection) |
|
|
|
|
.map((_id) => { |
|
|
|
|
const data = collection[key]; |
|
|
|
|
return { _id, data }; |
|
|
|
|
}) |
|
|
|
|
.filter( |
|
|
|
|
({ _id }) => |
|
|
|
|
filterRegex.test(_id) && (exactFinalTone.test(_id.substring(key.length)) || seeColor.test(key) || !colorBlind.test(_id)), |
|
|
|
|
) |
|
|
|
|
.sort(emojiSort(recents)) |
|
|
|
|
.slice(0, 10); |
|
|
|
|
}, |
|
|
|
|
getItemsFromServer: async () => { |
|
|
|
|
return []; |
|
|
|
|
}, |
|
|
|
|
getValue: (item) => `${item._id.substring(1)}`, |
|
|
|
|
renderItem: ({ item }) => <ComposerPopupEmoji {...item} />, |
|
|
|
|
}), |
|
|
|
|
return Object.keys(collection) |
|
|
|
|
.map((_id) => { |
|
|
|
|
const data = collection[key]; |
|
|
|
|
return { _id, data }; |
|
|
|
|
}) |
|
|
|
|
.filter( |
|
|
|
|
({ _id }) => |
|
|
|
|
filterRegex.test(_id) && (exactFinalTone.test(_id.substring(key.length)) || seeColor.test(key) || !colorBlind.test(_id)), |
|
|
|
|
) |
|
|
|
|
.sort(emojiSort(recents)) |
|
|
|
|
.slice(0, 10); |
|
|
|
|
}, |
|
|
|
|
getItemsFromServer: async () => { |
|
|
|
|
return []; |
|
|
|
|
}, |
|
|
|
|
getValue: (item) => `${item._id.substring(1)}`, |
|
|
|
|
renderItem: ({ item }) => <ComposerPopupEmoji {...item} />, |
|
|
|
|
}), |
|
|
|
|
createMessageBoxPopupConfig<ComposerBoxPopupEmojiProps>({ |
|
|
|
|
title: t('Emoji'), |
|
|
|
|
trigger: '\\+:', |
|
|
|
|
@ -352,7 +353,7 @@ const ComposerPopupProvider = ({ children, room }: { children: ReactNode; room: |
|
|
|
|
}, |
|
|
|
|
}), |
|
|
|
|
].filter(Boolean); |
|
|
|
|
}, [t, cannedResponseEnabled, isOmnichannel, recentEmojis, suggestionsCount, userSpotlight, rid, call]); |
|
|
|
|
}, [t, cannedResponseEnabled, isOmnichannel, recentEmojis, suggestionsCount, userSpotlight, rid, call, useEmoji]); |
|
|
|
|
|
|
|
|
|
return <ComposerPopupContext.Provider value={value} children={children} />; |
|
|
|
|
}; |
|
|
|
|
|