diff --git a/package.json b/package.json index 1eabb83d..5eb030f7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "4.3.0", + "version": "4.4.0-rc.1", "license": "MIT", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/src/config/config.ts b/src/config/config.ts index 1ea0437e..88674309 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -1,4 +1,5 @@ import { GetEmojiUrl } from '../components/emoji/Emoji'; +import { DataEmoji } from '../dataUtils/DataTypes'; import { emojiUrlByUnified } from '../dataUtils/emojiSelectors'; import { EmojiClickData, @@ -58,6 +59,7 @@ export function basePickerConfig(): PickerConfigInternal { ...basePreviewConfig }, searchPlaceHolder: 'Search', + showEmoji: undefined, skinTonesDisabled: false, suggestedEmojisMode: SuggestionMode.FREQUENT, theme: Theme.LIGHT, @@ -81,6 +83,7 @@ export type PickerConfigInternal = { height: PickerDimensions; width: PickerDimensions; getEmojiUrl: GetEmojiUrl; + showEmoji: undefined | ((emoji: DataEmoji) => boolean); }; export type PreviewConfig = { diff --git a/src/config/useConfig.ts b/src/config/useConfig.ts index 7874ffba..3bbd80b9 100644 --- a/src/config/useConfig.ts +++ b/src/config/useConfig.ts @@ -1,5 +1,6 @@ import { isSystemDarkTheme } from '../DomUtils/isDarkTheme'; import { usePickerConfig } from '../components/context/PickerConfigContext'; +import { DataEmoji } from '../dataUtils/DataTypes'; import { EmojiClickData, EmojiStyle, @@ -95,6 +96,13 @@ export function useGetEmojiUrlConfig(): ( return getEmojiUrl; } +export function useShowEmojiConfig(): + | undefined + | ((emoji: DataEmoji) => boolean) { + const { showEmoji } = usePickerConfig(); + return showEmoji; +} + function getDimension(dimensionConfig: PickerDimensions): PickerDimensions { return typeof dimensionConfig === 'number' ? `${dimensionConfig}px` diff --git a/src/hooks/useDisallowedEmojis.ts b/src/hooks/useDisallowedEmojis.ts index df018523..a112b5bc 100644 --- a/src/hooks/useDisallowedEmojis.ts +++ b/src/hooks/useDisallowedEmojis.ts @@ -1,28 +1,41 @@ import { useRef, useMemo } from 'react'; -import { useEmojiVersionConfig } from '../config/useConfig'; +import { useEmojiVersionConfig, useShowEmojiConfig } from '../config/useConfig'; import { DataEmoji } from '../dataUtils/DataTypes'; import { addedIn, allEmojis, emojiUnified } from '../dataUtils/emojiSelectors'; +import isFunction from '../predicates/isFunction'; export function useDisallowedEmojis() { const DisallowedEmojisRef = useRef>({}); const emojiVersionConfig = useEmojiVersionConfig(); + const shouldShowEmoji = useShowEmojiConfig(); return useMemo(() => { const emojiVersion = parseFloat(`${emojiVersionConfig}`); - if (!emojiVersionConfig || Number.isNaN(emojiVersion)) { + if ( + (!emojiVersionConfig || Number.isNaN(emojiVersion)) && + !shouldShowEmoji + ) { return DisallowedEmojisRef.current; } return allEmojis.reduce((disallowedEmojis, emoji) => { + if (isFunction(shouldShowEmoji) && !shouldShowEmoji(emoji)) { + disallowEmoji(); + } + if (addedInNewerVersion(emoji, emojiVersion)) { - disallowedEmojis[emojiUnified(emoji)] = true; + disallowEmoji(); } return disallowedEmojis; + + function disallowEmoji() { + disallowedEmojis[emojiUnified(emoji)] = true; + } }, DisallowedEmojisRef.current); - }, [emojiVersionConfig]); + }, [emojiVersionConfig, shouldShowEmoji]); } function addedInNewerVersion( diff --git a/src/hooks/useFilter.ts b/src/hooks/useFilter.ts index daa42f16..f973ba12 100644 --- a/src/hooks/useFilter.ts +++ b/src/hooks/useFilter.ts @@ -1,15 +1,16 @@ import { scrollTo } from '../DomUtils/scrollTo'; import { usePickerMainRef, - useSearchInputRef, + useSearchInputRef } from '../components/context/ElementRefContext'; import { FilterState, useFilterRef, - useSearchTermState, + useSearchTermState } from '../components/context/PickerContext'; import { DataEmoji } from '../dataUtils/DataTypes'; import { emojiNames } from '../dataUtils/emojiSelectors'; +import isFunction from '../predicates/isFunction'; import { useFocusSearchInput } from './useFocus'; @@ -19,7 +20,7 @@ function useSetFilterRef() { return function setFilter( setter: FilterState | ((current: FilterState) => FilterState) ): void { - if (typeof setter === 'function') { + if (isFunction(setter)) { return setFilter(setter(filterRef.current)); } @@ -67,7 +68,7 @@ export function useFilter() { return { onChange, searchTerm, - SearchInputRef, + SearchInputRef }; function onChange(inputValue: string) { @@ -87,9 +88,9 @@ export function useFilter() { return applySearch(nextValue); } - setFilterRef((current) => + setFilterRef(current => Object.assign(current, { - [nextValue]: filterEmojiObjectByKeyword(longestMatch, nextValue), + [nextValue]: filterEmojiObjectByKeyword(longestMatch, nextValue) }) ); applySearch(nextValue); @@ -129,14 +130,14 @@ function filterEmojiObjectByKeyword( } function hasMatch(emoji: DataEmoji, keyword: string): boolean { - return emojiNames(emoji).some((name) => name.includes(keyword)); + return emojiNames(emoji).some(name => name.includes(keyword)); } export function useIsEmojiFiltered(): (unified: string) => boolean { const { current: filter } = useFilterRef(); const [searchTerm] = useSearchTermState(); - return (unified) => isEmojiFilteredBySearchTerm(unified, filter, searchTerm); + return unified => isEmojiFilteredBySearchTerm(unified, filter, searchTerm); } function isEmojiFilteredBySearchTerm( @@ -167,7 +168,7 @@ function findLongestMatch( const longestMatchingKey = Object.keys(dict) .sort((a, b) => b.length - a.length) - .find((key) => keyword.includes(key)); + .find(key => keyword.includes(key)); if (longestMatchingKey) { return dict[longestMatchingKey]; diff --git a/src/predicates/isFunction.ts b/src/predicates/isFunction.ts new file mode 100644 index 00000000..0f177d17 --- /dev/null +++ b/src/predicates/isFunction.ts @@ -0,0 +1,5 @@ +export default function isFunction( + value: any +): value is (...args: any[]) => any { + return typeof value === 'function'; +} diff --git a/stories/picker.stories.tsx b/stories/picker.stories.tsx index a79e3922..f08a4b5b 100644 --- a/stories/picker.stories.tsx +++ b/stories/picker.stories.tsx @@ -9,6 +9,7 @@ import EmojiPicker, { Theme } from '../src'; import { Categories } from '../src/config/categoryConfig'; +import { DataEmoji } from '../src/dataUtils/DataTypes'; import { SuggestionMode } from '../src/types/exposedTypes'; const meta: Meta = { @@ -77,6 +78,13 @@ export const CustomSearchPlaceholder = (args: Props) => ( export const SkinTonesDisabled = (args: Props) => (