emoji-picker-react 4.20.7 → 4.20.9
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/DomUtils/focusElement.d.ts +1 -1
- package/dist/components/navigation/CategoryNavigation.d.ts +1 -1
- package/dist/emoji-picker-react.cjs.development.js +46 -36
- 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 +46 -36
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/DomUtils/focusElement.ts +9 -1
- package/src/components/navigation/CategoryNavigation.tsx +12 -5
- package/src/hooks/useEmojiPreviewEvents.ts +36 -27
package/package.json
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { NullableElement } from './selectors';
|
|
2
2
|
|
|
3
|
-
export function focusElement(
|
|
3
|
+
export function focusElement(
|
|
4
|
+
element: NullableElement,
|
|
5
|
+
shouldFocus?: () => boolean,
|
|
6
|
+
) {
|
|
4
7
|
if (!element) {
|
|
5
8
|
return;
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
requestAnimationFrame(() => {
|
|
12
|
+
// Rechecked here rather than at call time: focus may have moved in the
|
|
13
|
+
// meantime (e.g. hover scheduled focus, then the user tabbed out).
|
|
14
|
+
if (shouldFocus && !shouldFocus()) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
9
17
|
element.focus();
|
|
10
18
|
});
|
|
11
19
|
}
|
|
@@ -31,6 +31,17 @@ export function CategoryNavigation() {
|
|
|
31
31
|
const CategoryNavigationRef = useCategoryNavigationRef();
|
|
32
32
|
const hideCustomCategory = useShouldHideCustomEmojis();
|
|
33
33
|
|
|
34
|
+
const visibleCategories = categoriesConfig.filter(
|
|
35
|
+
categoryConfig =>
|
|
36
|
+
!(isCustomCategory(categoryConfig) && hideCustomCategory),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// A single tab navigates nowhere — hide the bar to reclaim its space.
|
|
40
|
+
// https://github.com/ealush/emoji-picker-react/issues/396
|
|
41
|
+
if (visibleCategories.length <= 1) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
return (
|
|
35
46
|
<div
|
|
36
47
|
className={cx(styles.nav)}
|
|
@@ -39,14 +50,10 @@ export function CategoryNavigation() {
|
|
|
39
50
|
id="epr-category-nav-id"
|
|
40
51
|
ref={CategoryNavigationRef}
|
|
41
52
|
>
|
|
42
|
-
{
|
|
53
|
+
{visibleCategories.map(categoryConfig => {
|
|
43
54
|
const category = categoryFromCategoryConfig(categoryConfig);
|
|
44
55
|
const isActiveCategory = category === activeCategory;
|
|
45
56
|
|
|
46
|
-
if (isCustomCategory(categoryConfig) && hideCustomCategory) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
57
|
const allowNavigation = !isSearchMode && !isActiveCategory;
|
|
51
58
|
|
|
52
59
|
return (
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
|
|
4
|
-
import { detectEmojyPartiallyBelowFold } from '../DomUtils/detectEmojyPartiallyBelowFold';
|
|
5
4
|
import { focusElement } from '../DomUtils/focusElement';
|
|
6
5
|
import {
|
|
7
6
|
allUnifiedFromEmojiElement,
|
|
8
7
|
buttonFromTarget,
|
|
9
8
|
} from '../DomUtils/selectors';
|
|
10
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
useBodyRef,
|
|
11
|
+
usePickerMainRef,
|
|
12
|
+
} from '../components/context/ElementRefContext';
|
|
11
13
|
import { PreviewEmoji } from '../components/footer/Preview';
|
|
12
14
|
|
|
13
15
|
import {
|
|
@@ -20,6 +22,7 @@ export function useEmojiPreviewEvents(
|
|
|
20
22
|
setPreviewEmoji: React.Dispatch<React.SetStateAction<PreviewEmoji>>,
|
|
21
23
|
) {
|
|
22
24
|
const BodyRef = useBodyRef();
|
|
25
|
+
const PickerMainRef = usePickerMainRef();
|
|
23
26
|
const isMouseDisallowed = useIsMouseDisallowed();
|
|
24
27
|
const allowMouseMove = useAllowMouseMove();
|
|
25
28
|
|
|
@@ -84,17 +87,41 @@ export function useEmojiPreviewEvents(
|
|
|
84
87
|
|
|
85
88
|
const button = buttonFromTarget(e.target as HTMLElement);
|
|
86
89
|
|
|
87
|
-
if (button) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
if (!button) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { unified, originalUnified } = allUnifiedFromEmojiElement(button);
|
|
95
|
+
|
|
96
|
+
if (!unified || !originalUnified) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setPreviewEmoji({
|
|
101
|
+
unified,
|
|
102
|
+
originalUnified,
|
|
103
|
+
});
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
// Let arrow-key navigation continue from the hovered emoji, but only
|
|
106
|
+
// when focus is already inside the picker (or nowhere meaningful).
|
|
107
|
+
// Pulling focus out of an external element steals the caret from
|
|
108
|
+
// host-app inputs (issue #320). The guard runs again inside the
|
|
109
|
+
// deferred callback in case focus moved out after this event.
|
|
110
|
+
if (!isExternalElementFocused()) {
|
|
111
|
+
focusElement(button, () => !isExternalElementFocused());
|
|
95
112
|
}
|
|
96
113
|
}
|
|
97
114
|
|
|
115
|
+
function isExternalElementFocused(): boolean {
|
|
116
|
+
const active = document.activeElement as HTMLElement | null;
|
|
117
|
+
|
|
118
|
+
if (!active || active === document.body || active === document.documentElement) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return !PickerMainRef.current?.contains(active);
|
|
123
|
+
}
|
|
124
|
+
|
|
98
125
|
return () => {
|
|
99
126
|
bodyRef?.removeEventListener('mouseover', onMouseOver);
|
|
100
127
|
bodyRef?.removeEventListener('mouseout', onLeave);
|
|
@@ -104,21 +131,3 @@ export function useEmojiPreviewEvents(
|
|
|
104
131
|
};
|
|
105
132
|
}, [BodyRef, allow, setPreviewEmoji, isMouseDisallowed, allowMouseMove]);
|
|
106
133
|
}
|
|
107
|
-
|
|
108
|
-
function handlePartiallyVisibleElementFocus(
|
|
109
|
-
button: HTMLElement,
|
|
110
|
-
setPreviewEmoji: React.Dispatch<React.SetStateAction<PreviewEmoji>>,
|
|
111
|
-
) {
|
|
112
|
-
const { unified, originalUnified } = allUnifiedFromEmojiElement(button);
|
|
113
|
-
|
|
114
|
-
if (!unified || !originalUnified) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
(document.activeElement as HTMLElement)?.blur?.();
|
|
119
|
-
|
|
120
|
-
setPreviewEmoji({
|
|
121
|
-
unified,
|
|
122
|
-
originalUnified,
|
|
123
|
-
});
|
|
124
|
-
}
|