emoji-picker-react 4.14.0 → 4.14.2
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.
- package/dist/components/context/PickerContext.d.ts +1 -0
- package/dist/emoji-picker-react.cjs.development.js +49 -12
- package/dist/emoji-picker-react.cjs.development.js.map +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js.map +1 -1
- package/dist/emoji-picker-react.esm.js +49 -12
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/preloadEmoji.d.ts +1 -1
- package/dist/hooks/useActiveCategoryScrollDetection.d.ts +4 -1
- package/dist/hooks/useEmojiVirtualization.d.ts +2 -1
- package/dist/hooks/useIsMounted.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/body/EmojiList.tsx +9 -2
- package/src/components/context/PickerContext.tsx +11 -2
- package/src/components/navigation/CategoryNavigation.tsx +3 -1
- package/src/hooks/preloadEmoji.ts +1 -1
- package/src/hooks/useActiveCategoryScrollDetection.ts +17 -5
- package/src/hooks/useCategoryHeight.ts +11 -2
- package/src/hooks/useEmojiVirtualization.tsx +11 -3
- package/src/hooks/useIsMounted.ts +11 -0
- package/dist/hooks/useIsEverMounted.d.ts +0 -1
- package/src/hooks/useIsEverMounted.ts +0 -14
|
@@ -2,7 +2,7 @@ import { GetEmojiUrl } from '../components/emoji/BaseEmojiProps';
|
|
|
2
2
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
3
3
|
import { EmojiStyle } from '../types/exposedTypes';
|
|
4
4
|
import { Dimensions } from '../virtualization/virtualizationHelpers';
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function preloadEmojiIfNeeded(emoji: undefined | DataEmoji, emojiStyles: EmojiStyle, scrollTop: number, clientHeight: number, topOffset: number, style: {
|
|
6
6
|
top: number;
|
|
7
7
|
} | undefined, dimensions: Dimensions, getEmojiUrl: GetEmojiUrl): void;
|
|
8
8
|
export declare function preloadEmoji(getEmojiUrl: GetEmojiUrl, emoji: undefined | DataEmoji, emojiStyle: EmojiStyle): void;
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
export declare function useActiveCategoryScrollDetection(setActiveCategory
|
|
1
|
+
export declare function useActiveCategoryScrollDetection({ setActiveCategory, setVisibleCategories }: {
|
|
2
|
+
setActiveCategory: (category: string) => void;
|
|
3
|
+
setVisibleCategories: (categories: string[]) => void;
|
|
4
|
+
}): void;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { DataEmojis } from '../dataUtils/DataTypes';
|
|
3
|
-
export declare function useEmojiVirtualization({ categoryEmojis, topOffset, onHeightReady, scrollTop }: {
|
|
3
|
+
export declare function useEmojiVirtualization({ categoryEmojis, topOffset, onHeightReady, scrollTop, isCategoryVisible }: {
|
|
4
4
|
categoryEmojis: DataEmojis;
|
|
5
5
|
topOffset: number;
|
|
6
6
|
onHeightReady: (height: number) => void;
|
|
7
7
|
scrollTop: number;
|
|
8
|
+
isCategoryVisible: boolean;
|
|
8
9
|
}): {
|
|
9
10
|
virtualizedCounter: number;
|
|
10
11
|
emojis: ReactNode[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useIsMounted(): boolean;
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ import { DataEmojis } from '../../dataUtils/DataTypes';
|
|
|
13
13
|
import { useGetEmojisByCategory } from '../../dataUtils/emojiSelectors';
|
|
14
14
|
import { useEmojiVirtualization } from '../../hooks/useEmojiVirtualization';
|
|
15
15
|
import { useEmojiListRef } from '../context/ElementRefContext';
|
|
16
|
+
import { useVisibleCategoriesState } from '../context/PickerContext';
|
|
16
17
|
|
|
17
18
|
import { EmojiCategory } from './EmojiCategory';
|
|
18
19
|
|
|
@@ -46,7 +47,10 @@ export function EmojiList({ scrollTop }: { scrollTop: number }) {
|
|
|
46
47
|
topOffset={currentOffset}
|
|
47
48
|
onHeightReady={height => {
|
|
48
49
|
if (categoryHeights[category] !== height) {
|
|
49
|
-
setCategoryHeights(prev => ({
|
|
50
|
+
setCategoryHeights(prev => ({
|
|
51
|
+
...prev,
|
|
52
|
+
[category]: height
|
|
53
|
+
}));
|
|
50
54
|
}
|
|
51
55
|
}}
|
|
52
56
|
scrollTop={scrollTop}
|
|
@@ -71,11 +75,14 @@ function RenderCategory({
|
|
|
71
75
|
onHeightReady: (height: number) => void;
|
|
72
76
|
scrollTop: number;
|
|
73
77
|
}) {
|
|
78
|
+
const [visibleCategories] = useVisibleCategoriesState();
|
|
79
|
+
|
|
74
80
|
const { virtualizedCounter, emojis, dimensions } = useEmojiVirtualization({
|
|
75
81
|
categoryEmojis,
|
|
76
82
|
topOffset,
|
|
77
83
|
onHeightReady,
|
|
78
|
-
scrollTop
|
|
84
|
+
scrollTop,
|
|
85
|
+
isCategoryVisible: visibleCategories.includes(categoryConfig.category)
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
return (
|
|
@@ -35,6 +35,7 @@ export function PickerContextProvider({ children }: Props) {
|
|
|
35
35
|
const emojiVariationPickerState = useState<DataEmoji | null>(null);
|
|
36
36
|
const reactionsModeState = useState(reactionsDefaultOpen);
|
|
37
37
|
const [isPastInitialLoad, setIsPastInitialLoad] = useState(false);
|
|
38
|
+
const visibleCategoriesState = useState<string[]>([]);
|
|
38
39
|
|
|
39
40
|
useMarkInitialLoad(setIsPastInitialLoad);
|
|
40
41
|
|
|
@@ -53,7 +54,8 @@ export function PickerContextProvider({ children }: Props) {
|
|
|
53
54
|
searchTerm,
|
|
54
55
|
skinToneFanOpenState,
|
|
55
56
|
suggestedUpdateState,
|
|
56
|
-
reactionsModeState
|
|
57
|
+
reactionsModeState,
|
|
58
|
+
visibleCategoriesState
|
|
57
59
|
}}
|
|
58
60
|
>
|
|
59
61
|
{children}
|
|
@@ -77,6 +79,7 @@ const PickerContext = React.createContext<{
|
|
|
77
79
|
disallowMouseRef: React.MutableRefObject<boolean>;
|
|
78
80
|
disallowedEmojisRef: React.MutableRefObject<Record<string, boolean>>;
|
|
79
81
|
reactionsModeState: ReactState<boolean>;
|
|
82
|
+
visibleCategoriesState: ReactState<Array<string>>;
|
|
80
83
|
}>({
|
|
81
84
|
activeCategoryState: [null, () => {}],
|
|
82
85
|
activeSkinTone: [SkinTones.NEUTRAL, () => {}],
|
|
@@ -90,7 +93,8 @@ const PickerContext = React.createContext<{
|
|
|
90
93
|
searchTerm: ['', () => new Promise<string>(() => undefined)],
|
|
91
94
|
skinToneFanOpenState: [false, () => {}],
|
|
92
95
|
suggestedUpdateState: [Date.now(), () => {}],
|
|
93
|
-
reactionsModeState: [false, () => {}]
|
|
96
|
+
reactionsModeState: [false, () => {}],
|
|
97
|
+
visibleCategoriesState: [[], () => []]
|
|
94
98
|
});
|
|
95
99
|
|
|
96
100
|
type Props = Readonly<{
|
|
@@ -155,6 +159,11 @@ export function useDisallowedEmojisRef() {
|
|
|
155
159
|
return disallowedEmojisRef;
|
|
156
160
|
}
|
|
157
161
|
|
|
162
|
+
export function useVisibleCategoriesState() {
|
|
163
|
+
const { visibleCategoriesState } = React.useContext(PickerContext);
|
|
164
|
+
return visibleCategoriesState;
|
|
165
|
+
}
|
|
166
|
+
|
|
158
167
|
export function useUpdateSuggested(): [number, () => void] {
|
|
159
168
|
const { suggestedUpdateState } = React.useContext(PickerContext);
|
|
160
169
|
|
|
@@ -11,13 +11,15 @@ import { useScrollCategoryIntoView } from '../../hooks/useScrollCategoryIntoView
|
|
|
11
11
|
import { useShouldHideCustomEmojis } from '../../hooks/useShouldHideCustomEmojis';
|
|
12
12
|
import { isCustomCategory } from '../../typeRefinements/typeRefinements';
|
|
13
13
|
import { useCategoryNavigationRef } from '../context/ElementRefContext';
|
|
14
|
+
import { useVisibleCategoriesState } from '../context/PickerContext';
|
|
14
15
|
|
|
15
16
|
import { CategoryButton } from './CategoryButton';
|
|
16
17
|
|
|
17
18
|
export function CategoryNavigation() {
|
|
18
19
|
const [activeCategory, setActiveCategory] = useState<string | null>(null);
|
|
20
|
+
const [, setVisibleCategories] = useVisibleCategoriesState();
|
|
19
21
|
const scrollCategoryIntoView = useScrollCategoryIntoView();
|
|
20
|
-
useActiveCategoryScrollDetection(setActiveCategory);
|
|
22
|
+
useActiveCategoryScrollDetection({ setActiveCategory, setVisibleCategories });
|
|
21
23
|
const isSearchMode = useIsSearchMode();
|
|
22
24
|
|
|
23
25
|
const categoriesConfig = useCategoriesConfig();
|
|
@@ -5,7 +5,7 @@ import { EmojiStyle } from '../types/exposedTypes';
|
|
|
5
5
|
import { Dimensions } from '../virtualization/virtualizationHelpers';
|
|
6
6
|
|
|
7
7
|
// eslint-disable-next-line max-params
|
|
8
|
-
export function
|
|
8
|
+
export function preloadEmojiIfNeeded(
|
|
9
9
|
emoji: undefined | DataEmoji,
|
|
10
10
|
emojiStyles: EmojiStyle,
|
|
11
11
|
scrollTop: number,
|
|
@@ -4,13 +4,17 @@ import { categoryNameFromDom } from '../DomUtils/categoryNameFromDom';
|
|
|
4
4
|
import { asSelectors, ClassNames } from '../DomUtils/classNames';
|
|
5
5
|
import { useBodyRef } from '../components/context/ElementRefContext';
|
|
6
6
|
|
|
7
|
-
export function useActiveCategoryScrollDetection(
|
|
8
|
-
setActiveCategory
|
|
9
|
-
|
|
7
|
+
export function useActiveCategoryScrollDetection({
|
|
8
|
+
setActiveCategory,
|
|
9
|
+
setVisibleCategories
|
|
10
|
+
}: {
|
|
11
|
+
setActiveCategory: (category: string) => void;
|
|
12
|
+
setVisibleCategories: (categories: string[]) => void;
|
|
13
|
+
}) {
|
|
10
14
|
const BodyRef = useBodyRef();
|
|
11
15
|
|
|
12
16
|
useEffect(() => {
|
|
13
|
-
const visibleCategories = new Map();
|
|
17
|
+
const visibleCategories = new Map<string, number>();
|
|
14
18
|
const bodyRef = BodyRef.current;
|
|
15
19
|
const observer = new IntersectionObserver(
|
|
16
20
|
entries => {
|
|
@@ -20,10 +24,18 @@ export function useActiveCategoryScrollDetection(
|
|
|
20
24
|
|
|
21
25
|
for (const entry of entries) {
|
|
22
26
|
const id = categoryNameFromDom(entry.target);
|
|
27
|
+
|
|
28
|
+
if (!id) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
visibleCategories.set(id, entry.intersectionRatio);
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
const ratios = Array.from(visibleCategories);
|
|
36
|
+
setVisibleCategories(
|
|
37
|
+
ratios.filter(([_, ratio]) => ratio > 0).map(([id]) => id)
|
|
38
|
+
);
|
|
27
39
|
const lastCategory = ratios[ratios.length - 1];
|
|
28
40
|
|
|
29
41
|
if (lastCategory[1] == 1) {
|
|
@@ -44,5 +56,5 @@ export function useActiveCategoryScrollDetection(
|
|
|
44
56
|
bodyRef?.querySelectorAll(asSelectors(ClassNames.category)).forEach(el => {
|
|
45
57
|
observer.observe(el);
|
|
46
58
|
});
|
|
47
|
-
}, [BodyRef, setActiveCategory]);
|
|
59
|
+
}, [BodyRef, setActiveCategory, setVisibleCategories]);
|
|
48
60
|
}
|
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
useEmojiListRef,
|
|
6
6
|
usePickerMainRef
|
|
7
7
|
} from '../components/context/ElementRefContext';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
useReactionsModeState,
|
|
10
|
+
useVisibleCategoriesState
|
|
11
|
+
} from '../components/context/PickerContext';
|
|
9
12
|
|
|
10
13
|
const EMOJI_SIZE_DEFAULT = 32;
|
|
11
14
|
|
|
@@ -22,6 +25,7 @@ export function useCategoryHeight(
|
|
|
22
25
|
const [isReactionsMode] = useReactionsModeState();
|
|
23
26
|
const PickerMainRef = usePickerMainRef();
|
|
24
27
|
const emojiSizeRef = React.useRef<number | undefined>();
|
|
28
|
+
const [visibleCategories] = useVisibleCategoriesState();
|
|
25
29
|
const [dimensions, setDimensions] = React.useState<{
|
|
26
30
|
categoryHeight: number;
|
|
27
31
|
emojisPerRow: number;
|
|
@@ -54,7 +58,12 @@ export function useCategoryHeight(
|
|
|
54
58
|
// Recompute on data-count changes and when reactions mode toggles
|
|
55
59
|
React.useEffect(() => {
|
|
56
60
|
computeAndSetDimensions();
|
|
57
|
-
}, [
|
|
61
|
+
}, [
|
|
62
|
+
emojiCount,
|
|
63
|
+
isReactionsMode,
|
|
64
|
+
computeAndSetDimensions,
|
|
65
|
+
visibleCategories.length
|
|
66
|
+
]);
|
|
58
67
|
|
|
59
68
|
// Listen to transitionend on the picker root (where height transition occurs)
|
|
60
69
|
React.useEffect(() => {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
shouldVirtualize
|
|
18
18
|
} from '../virtualization/virtualizationHelpers';
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import { preloadEmojiIfNeeded } from './preloadEmoji';
|
|
21
21
|
import { useCategoryHeight } from './useCategoryHeight';
|
|
22
22
|
import { useIsEmojiDisallowed } from './useDisallowedEmojis';
|
|
23
23
|
import { useIsEmojiHidden } from './useIsEmojiHidden';
|
|
@@ -26,12 +26,14 @@ export function useEmojiVirtualization({
|
|
|
26
26
|
categoryEmojis,
|
|
27
27
|
topOffset,
|
|
28
28
|
onHeightReady,
|
|
29
|
-
scrollTop
|
|
29
|
+
scrollTop,
|
|
30
|
+
isCategoryVisible
|
|
30
31
|
}: {
|
|
31
32
|
categoryEmojis: DataEmojis;
|
|
32
33
|
topOffset: number;
|
|
33
34
|
onHeightReady: (height: number) => void;
|
|
34
35
|
scrollTop: number;
|
|
36
|
+
isCategoryVisible: boolean;
|
|
35
37
|
}) {
|
|
36
38
|
const isEmojiHidden = useIsEmojiHidden();
|
|
37
39
|
const lazyLoadEmojis = useLazyLoadEmojisConfig();
|
|
@@ -74,7 +76,7 @@ export function useEmojiVirtualization({
|
|
|
74
76
|
})
|
|
75
77
|
) {
|
|
76
78
|
virtualizedCounter++;
|
|
77
|
-
|
|
79
|
+
preloadEmojiIfNeeded(
|
|
78
80
|
emoji,
|
|
79
81
|
emojiStyle,
|
|
80
82
|
scrollTop,
|
|
@@ -86,6 +88,12 @@ export function useEmojiVirtualization({
|
|
|
86
88
|
);
|
|
87
89
|
return accumulator;
|
|
88
90
|
}
|
|
91
|
+
|
|
92
|
+
if (!isCategoryVisible) {
|
|
93
|
+
virtualizedCounter++;
|
|
94
|
+
return accumulator;
|
|
95
|
+
}
|
|
96
|
+
|
|
89
97
|
accumulator.push(
|
|
90
98
|
<ClickableEmoji
|
|
91
99
|
showVariations={showVariations}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function useIsEverMounted(): boolean;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
let isEverMounted = false;
|
|
4
|
-
|
|
5
|
-
export function useIsEverMounted() {
|
|
6
|
-
const [isMounted, setIsMounted] = React.useState(isEverMounted);
|
|
7
|
-
|
|
8
|
-
React.useEffect(() => {
|
|
9
|
-
setIsMounted(true);
|
|
10
|
-
isEverMounted = true;
|
|
11
|
-
}, []);
|
|
12
|
-
|
|
13
|
-
return isMounted || isEverMounted;
|
|
14
|
-
}
|