emoji-picker-react 4.22.1 → 4.22.3
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/README.md +5 -1
- 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/llms.txt +5 -1
- package/package.json +26 -2
- 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/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ The most popular fully customizable emoji picker for React.
|
|
|
11
11
|
|
|
12
12
|
[](https://www.npmjs.com/package/emoji-picker-react)
|
|
13
13
|
|
|
14
|
-
**[Live Demo](https://ealush.com/emoji-picker-react)** | **[Report a Bug](https://github.com/ealush/emoji-picker-react/issues)**
|
|
14
|
+
**[Live Demo](https://ealush.com/emoji-picker-react)** | **[Report a Bug](https://github.com/ealush/emoji-picker-react/issues)** | **[Sponsor](https://github.com/sponsors/ealush)**
|
|
15
15
|
|
|
16
16
|

|
|
17
17
|
|
|
@@ -117,6 +117,10 @@ On older versions only, the workaround was adding this to your HTML:
|
|
|
117
117
|
</script>
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
## Support Emoji Picker React
|
|
121
|
+
|
|
122
|
+
Emoji Picker React is independently maintained. If your team relies on it, you can help fund ongoing maintenance and releases through [GitHub Sponsors](https://github.com/sponsors/ealush). Organizations can also support the project through [Tidelift](https://tidelift.com/subscription/pkg/npm-emoji-picker-react).
|
|
123
|
+
|
|
120
124
|
## More from the maintainer
|
|
121
125
|
|
|
122
126
|
Building complex forms? Check out [**Vest**](https://vestjs.dev) — a validation framework for stateful, async, and dependent validation.
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.22.
|
|
2
|
+
"version": "4.22.3",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -26,6 +26,30 @@
|
|
|
26
26
|
"type": "git",
|
|
27
27
|
"url": "https://github.com/ealush/emoji-picker-react.git"
|
|
28
28
|
},
|
|
29
|
+
"funding": [
|
|
30
|
+
{
|
|
31
|
+
"type": "github",
|
|
32
|
+
"url": "https://github.com/sponsors/ealush"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "tidelift",
|
|
36
|
+
"url": "https://tidelift.com/subscription/pkg/npm-emoji-picker-react"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"overrides": {
|
|
40
|
+
"decode-uri-component": "0.2.2",
|
|
41
|
+
"deep-object-diff": "1.1.9",
|
|
42
|
+
"ua-parser-js": "0.7.41",
|
|
43
|
+
"minimist": "1.2.8",
|
|
44
|
+
"loader-utils": "2.0.4",
|
|
45
|
+
"form-data": "4.0.6",
|
|
46
|
+
"request": {
|
|
47
|
+
"form-data": "2.5.6"
|
|
48
|
+
},
|
|
49
|
+
"tsconfig-paths": {
|
|
50
|
+
"json5": "1.0.2"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
29
53
|
"scripts": {
|
|
30
54
|
"start": "tsdx watch",
|
|
31
55
|
"build": "npm run build:data:src && npm run type-check && tsdx build --transpileOnly && npm run build:data:dist && npm run docs:llms",
|
|
@@ -122,7 +146,7 @@
|
|
|
122
146
|
"tsdx": "^0.14.1",
|
|
123
147
|
"tslib": "^2.4.0",
|
|
124
148
|
"typescript": "^4.7.4",
|
|
125
|
-
"vitest": "^
|
|
149
|
+
"vitest": "^4.1.11"
|
|
126
150
|
},
|
|
127
151
|
"dependencies": {
|
|
128
152
|
"shipstyles": "1.0.0"
|
|
@@ -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
|
}
|