emoji-picker-react 4.22.1 → 4.22.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/emoji-picker-react.cjs.development.js +47 -24
- 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 +47 -24
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/useActiveCategoryScrollDetection.d.ts +6 -6
- package/package.json +1 -1
- package/src/components/navigation/CategoryNavigation.tsx +3 -7
- package/src/config/compareConfig.ts +62 -21
- package/src/hooks/useActiveCategoryScrollDetection.ts +7 -7
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { CategoriesConfig } from '../config/categoryConfig';
|
|
2
|
+
export declare function useActiveCategoryScrollDetection({ setActiveCategory, setVisibleCategories, categories, }: {
|
|
2
3
|
setActiveCategory: (category: string) => void;
|
|
3
4
|
setVisibleCategories: (categories: string[]) => void;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* added or removed
|
|
8
|
-
* stop contributing; unrelated renders keep the same key.
|
|
6
|
+
* Effective category list. The merged array reference only changes when
|
|
7
|
+
* the configuration is re-merged, so the observer re-subscribes exactly
|
|
8
|
+
* when sections are added or removed — no serialization involved.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
categories: CategoriesConfig;
|
|
11
11
|
}): void;
|
package/package.json
CHANGED
|
@@ -36,16 +36,12 @@ export function CategoryNavigation() {
|
|
|
36
36
|
const hideCustomCategory = useShouldHideCustomEmojis();
|
|
37
37
|
const { customGroups, emojiData } = usePickerDataContext();
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
// added/removed
|
|
41
|
-
// unless the effective category list changes.
|
|
42
|
-
const categoryIdentitiesKey = categoriesConfig
|
|
43
|
-
.map(entry => categoryIdFromCategoryConfig(entry))
|
|
44
|
-
.join('|');
|
|
39
|
+
// The observer re-subscribes when the merged categories reference
|
|
40
|
+
// changes (sections added/removed); the reference is stable otherwise.
|
|
45
41
|
useActiveCategoryScrollDetection({
|
|
46
42
|
setActiveCategory,
|
|
47
43
|
setVisibleCategories,
|
|
48
|
-
|
|
44
|
+
categories: categoriesConfig,
|
|
49
45
|
});
|
|
50
46
|
|
|
51
47
|
const visibleCategories = categoriesConfig.filter(categoryConfig => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Categories, CategoryConfig } from '../types/exposedTypes';
|
|
2
|
+
|
|
1
3
|
import { UserCategoryConfig } from './categoryConfig';
|
|
2
4
|
import { PickerConfig } from './config';
|
|
3
5
|
import { CustomEmoji } from './customEmojiConfig';
|
|
@@ -27,35 +29,74 @@ export function compareConfig(prev: PickerConfig, next: PickerConfig) {
|
|
|
27
29
|
prev.searchDisabled === next.searchDisabled &&
|
|
28
30
|
prev.skinTonePickerLocation === next.skinTonePickerLocation &&
|
|
29
31
|
prevCustomEmojis.length === nextCustomEmojis.length &&
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
customEmojisEqual(prevCustomEmojis, nextCustomEmojis) &&
|
|
33
|
+
categoriesEqual(prev.categories, next.categories) &&
|
|
32
34
|
prev.emojiData === next.emojiData
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
|
-
*
|
|
38
|
-
* swaps, which would leave merged categories, search, and
|
|
39
|
+
* Structural content equality for custom emojis. Length alone misses
|
|
40
|
+
* regroups and swaps, which would leave merged categories, search, and
|
|
41
|
+
* sections stale. Fields are compared element-wise (never serialized
|
|
42
|
+
* with delimiters) so user-controlled values cannot collide.
|
|
43
|
+
*/
|
|
44
|
+
function customEmojisEqual(
|
|
45
|
+
prev: CustomEmoji[],
|
|
46
|
+
next: CustomEmoji[],
|
|
47
|
+
): boolean {
|
|
48
|
+
if (prev.length !== next.length) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return prev.every((emoji, index) => {
|
|
52
|
+
const other = next[index];
|
|
53
|
+
return (
|
|
54
|
+
emoji.id === other.id &&
|
|
55
|
+
(emoji.group ?? '') === (other.group ?? '') &&
|
|
56
|
+
emoji.imgUrl === other.imgUrl &&
|
|
57
|
+
emoji.names.length === other.names.length &&
|
|
58
|
+
emoji.names.every((name, nameIndex) => name === other.names[nameIndex])
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Structural content equality for the categories input. Order, labels,
|
|
65
|
+
* group selection, and icon identity all flow into the merged
|
|
66
|
+
* configuration. Icons compare by reference: swapping one icon element
|
|
67
|
+
* for another must rebuild, while a stable reference stays cheap.
|
|
39
68
|
*/
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
69
|
+
function categoriesEqual(
|
|
70
|
+
prev: UserCategoryConfig | undefined,
|
|
71
|
+
next: UserCategoryConfig | undefined,
|
|
72
|
+
): boolean {
|
|
73
|
+
const prevEntries = prev ?? [];
|
|
74
|
+
const nextEntries = next ?? [];
|
|
75
|
+
if (prevEntries.length !== nextEntries.length) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return prevEntries.every((entry, index) =>
|
|
79
|
+
categoryEntriesEqual(entry, nextEntries[index]),
|
|
80
|
+
);
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
84
|
+
* One categories entry compared structurally. Icons compare by reference:
|
|
85
|
+
* swapping one icon element for another rebuilds, a stable reference stays
|
|
86
|
+
* cheap. Delimited serialization is avoided so user-controlled values
|
|
87
|
+
* cannot collide.
|
|
52
88
|
*/
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
89
|
+
function categoryEntriesEqual(
|
|
90
|
+
entry: Categories | CategoryConfig,
|
|
91
|
+
other: Categories | CategoryConfig,
|
|
92
|
+
): boolean {
|
|
93
|
+
if (typeof entry === 'string' || typeof other === 'string') {
|
|
94
|
+
return entry === other;
|
|
95
|
+
}
|
|
96
|
+
return (
|
|
97
|
+
entry.category === other.category &&
|
|
98
|
+
entry.name === other.name &&
|
|
99
|
+
(entry.group ?? '') === (other.group ?? '') &&
|
|
100
|
+
entry.icon === other.icon
|
|
101
|
+
);
|
|
61
102
|
}
|
|
@@ -3,21 +3,21 @@ import { useEffect } from 'react';
|
|
|
3
3
|
import { categoryNameFromDom } from '../DomUtils/categoryNameFromDom';
|
|
4
4
|
import { asSelectors, ClassNames } from '../DomUtils/classNames';
|
|
5
5
|
import { useBodyRef } from '../components/context/ElementRefContext';
|
|
6
|
+
import { CategoriesConfig } from '../config/categoryConfig';
|
|
6
7
|
|
|
7
8
|
export function useActiveCategoryScrollDetection({
|
|
8
9
|
setActiveCategory,
|
|
9
10
|
setVisibleCategories,
|
|
10
|
-
|
|
11
|
+
categories,
|
|
11
12
|
}: {
|
|
12
13
|
setActiveCategory: (category: string) => void;
|
|
13
14
|
setVisibleCategories: (categories: string[]) => void;
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* added or removed
|
|
18
|
-
* stop contributing; unrelated renders keep the same key.
|
|
16
|
+
* Effective category list. The merged array reference only changes when
|
|
17
|
+
* the configuration is re-merged, so the observer re-subscribes exactly
|
|
18
|
+
* when sections are added or removed — no serialization involved.
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
categories: CategoriesConfig;
|
|
21
21
|
}) {
|
|
22
22
|
const BodyRef = useBodyRef();
|
|
23
23
|
|
|
@@ -75,5 +75,5 @@ export function useActiveCategoryScrollDetection({
|
|
|
75
75
|
return () => {
|
|
76
76
|
observer.disconnect();
|
|
77
77
|
};
|
|
78
|
-
}, [BodyRef,
|
|
78
|
+
}, [BodyRef, categories, setActiveCategory, setVisibleCategories]);
|
|
79
79
|
}
|