emoji-picker-react 4.0.6 → 4.0.7
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/classNames.d.ts +1 -0
- package/dist/DomUtils/scrollTo.d.ts +2 -0
- package/dist/DomUtils/selectors.d.ts +6 -0
- package/dist/components/atoms/Button.d.ts +6 -0
- package/dist/emoji-picker-react.cjs.development.css +2 -2
- package/dist/emoji-picker-react.cjs.development.js +191 -117
- 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 +193 -119
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/useFilter.d.ts +2 -1
- package/package.json +1 -1
- package/src/DomUtils/classNames.ts +1 -0
- package/src/DomUtils/keyboardNavigation.ts +7 -1
- package/src/DomUtils/scrollTo.ts +33 -3
- package/src/DomUtils/selectors.ts +60 -4
- package/src/EmojiPickerReact.css +1 -1
- package/src/components/atoms/Button.tsx +22 -0
- package/src/components/body/Body.tsx +2 -1
- package/src/components/emoji/Emoji.tsx +3 -3
- package/src/components/header/Search.css +36 -8
- package/src/components/header/Search.tsx +13 -5
- package/src/components/header/SkinTonePicker.tsx +3 -3
- package/src/components/navigation/CategoryNavigation.tsx +5 -2
- package/src/config/config.ts +3 -3
- package/src/hooks/useFilter.ts +24 -9
- package/src/hooks/useKeyboardNavigation.ts +1 -6
|
@@ -2,9 +2,10 @@ import { DataEmoji } from '../dataUtils/DataTypes';
|
|
|
2
2
|
export declare function useClearSearch(): () => void;
|
|
3
3
|
export declare function useAppendSearch(): (str: string) => void;
|
|
4
4
|
export declare function useFilter(): {
|
|
5
|
-
onChange: (
|
|
5
|
+
onChange: (inputValue: string) => void;
|
|
6
6
|
searchTerm: string;
|
|
7
7
|
SearchInputRef: import("../components/context/ElementRefContext").ElementRef<HTMLInputElement>;
|
|
8
8
|
};
|
|
9
9
|
export declare function useIsEmojiFiltered(): (unified: string) => boolean;
|
|
10
10
|
export declare type FilterDict = Record<string, DataEmoji>;
|
|
11
|
+
export declare function getNormalizedSearchTerm(str: string): string;
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
rowNumber
|
|
9
9
|
} from './elementPositionInRow';
|
|
10
10
|
import { focusElement } from './focusElement';
|
|
11
|
+
import { scrollEmojiAboveLabel } from './scrollTo';
|
|
11
12
|
import {
|
|
12
13
|
allVisibleEmojis,
|
|
13
14
|
closestCategory,
|
|
@@ -22,7 +23,9 @@ import {
|
|
|
22
23
|
} from './selectors';
|
|
23
24
|
|
|
24
25
|
export function focusFirstVisibleEmoji(parent: NullableElement) {
|
|
25
|
-
|
|
26
|
+
const emoji = firstVisibleEmoji(parent);
|
|
27
|
+
focusElement(emoji);
|
|
28
|
+
scrollEmojiAboveLabel(emoji);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
export function focusAndClickFirstVisibleEmoji(parent: NullableElement) {
|
|
@@ -48,6 +51,7 @@ export function focusNextVisibleEmoji(element: NullableElement) {
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
focusElement(next);
|
|
54
|
+
scrollEmojiAboveLabel(next);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
export function focusPrevVisibleEmoji(element: NullableElement) {
|
|
@@ -62,6 +66,7 @@ export function focusPrevVisibleEmoji(element: NullableElement) {
|
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
focusElement(prev);
|
|
69
|
+
scrollEmojiAboveLabel(prev);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
export function focusVisibleEmojiOneRowUp(
|
|
@@ -79,6 +84,7 @@ export function focusVisibleEmojiOneRowUp(
|
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
focusElement(prev);
|
|
87
|
+
scrollEmojiAboveLabel(prev);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
export function focusVisibleEmojiOneRowDown(element: NullableElement) {
|
package/src/DomUtils/scrollTo.ts
CHANGED
|
@@ -2,12 +2,20 @@ import { useCallback } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { useBodyRef } from '../components/context/ElementRefContext';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
categoryLabelHeight,
|
|
7
|
+
closestCategory,
|
|
8
|
+
closestScrollBody,
|
|
9
|
+
emojiDistanceFromScrollTop,
|
|
10
|
+
isEmojiBehindLabel,
|
|
11
|
+
NullableElement,
|
|
12
|
+
queryScrollBody
|
|
13
|
+
} from './selectors';
|
|
6
14
|
|
|
7
15
|
export function scrollTo(root: NullableElement, top: number = 0) {
|
|
8
|
-
const $eprBody = root
|
|
16
|
+
const $eprBody = queryScrollBody(root);
|
|
9
17
|
|
|
10
|
-
if (
|
|
18
|
+
if (!$eprBody) {
|
|
11
19
|
return;
|
|
12
20
|
}
|
|
13
21
|
|
|
@@ -16,6 +24,18 @@ export function scrollTo(root: NullableElement, top: number = 0) {
|
|
|
16
24
|
});
|
|
17
25
|
}
|
|
18
26
|
|
|
27
|
+
export function scrollBy(root: NullableElement, by: number): void {
|
|
28
|
+
const $eprBody = queryScrollBody(root);
|
|
29
|
+
|
|
30
|
+
if (!$eprBody) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
requestAnimationFrame(() => {
|
|
35
|
+
$eprBody.scrollTop = $eprBody.scrollTop + by;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
export function useScrollTo() {
|
|
20
40
|
const BodyRef = useBodyRef();
|
|
21
41
|
|
|
@@ -30,3 +50,13 @@ export function useScrollTo() {
|
|
|
30
50
|
[BodyRef]
|
|
31
51
|
);
|
|
32
52
|
}
|
|
53
|
+
|
|
54
|
+
export function scrollEmojiAboveLabel(emoji: NullableElement) {
|
|
55
|
+
if (!isEmojiBehindLabel(emoji)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const scrollBody = closestScrollBody(emoji);
|
|
60
|
+
const by = emojiDistanceFromScrollTop(emoji);
|
|
61
|
+
scrollBy(scrollBody, -(categoryLabelHeight(closestCategory(emoji)) - by));
|
|
62
|
+
}
|
|
@@ -22,6 +22,14 @@ export function buttonFromTarget(
|
|
|
22
22
|
return emojiElement?.closest(EmojiButtonSelector) ?? null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
export function isEmojiButton(element: NullableElement): boolean {
|
|
26
|
+
if (!element) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return element.matches(EmojiButtonSelector);
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
export function emojiFromElement(
|
|
26
34
|
element: NullableElement
|
|
27
35
|
): [DataEmoji, string] | [] {
|
|
@@ -71,15 +79,63 @@ export function emojiTrueOffsetTop(element: NullableElement): number {
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
const button = buttonFromTarget(element);
|
|
74
|
-
const
|
|
75
|
-
const category = closestCategory(categoryWithoutLabel);
|
|
82
|
+
const category = closestCategory(button);
|
|
76
83
|
|
|
77
84
|
// compensate for the label height
|
|
78
|
-
const labelHeight =
|
|
79
|
-
(category?.clientHeight ?? 0) - (categoryWithoutLabel?.clientHeight ?? 0);
|
|
85
|
+
const labelHeight = categoryLabelHeight(category);
|
|
80
86
|
|
|
81
87
|
return elementOffsetTop(button) + elementOffsetTop(category) + labelHeight;
|
|
82
88
|
}
|
|
89
|
+
|
|
90
|
+
export function categoryLabelHeight(category: NullableElement): number {
|
|
91
|
+
if (!category) {
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const categoryWithoutLabel = category.querySelector(
|
|
96
|
+
asSelectors(ClassNames.categoryContent)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
(category?.clientHeight ?? 0) - (categoryWithoutLabel?.clientHeight ?? 0)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function isEmojiBehindLabel(emoji: NullableElement): boolean {
|
|
105
|
+
if (!emoji) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
emojiDistanceFromScrollTop(emoji) <
|
|
111
|
+
categoryLabelHeight(closestCategory(emoji))
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function queryScrollBody(root: NullableElement): NullableElement {
|
|
116
|
+
return root
|
|
117
|
+
? root.matches(asSelectors(ClassNames.scrollBody))
|
|
118
|
+
? root
|
|
119
|
+
: root.querySelector(ClassNames.scrollBody)
|
|
120
|
+
: null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function emojiDistanceFromScrollTop(emoji: NullableElement): number {
|
|
124
|
+
if (!emoji) {
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return emojiTrueOffsetTop(emoji) - (closestScrollBody(emoji)?.scrollTop ?? 0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function closestScrollBody(element: NullableElement): NullableElement {
|
|
132
|
+
if (!element) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return element.closest(asSelectors(ClassNames.scrollBody)) ?? null;
|
|
137
|
+
}
|
|
138
|
+
|
|
83
139
|
export function emojiTruOffsetLeft(element: NullableElement): number {
|
|
84
140
|
const button = buttonFromTarget(element);
|
|
85
141
|
const category = closestCategory(button);
|
package/src/EmojiPickerReact.css
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
interface Props
|
|
5
|
+
extends React.DetailedHTMLProps<
|
|
6
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
7
|
+
HTMLButtonElement
|
|
8
|
+
> {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Button(props: Props) {
|
|
13
|
+
return (
|
|
14
|
+
<button
|
|
15
|
+
type="button"
|
|
16
|
+
{...props}
|
|
17
|
+
className={clsx('epr-btn', props.className)}
|
|
18
|
+
>
|
|
19
|
+
{props.children}
|
|
20
|
+
</button>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { ClassNames } from '../../DomUtils/classNames';
|
|
3
4
|
import { useOnMouseMove } from '../../hooks/useDisallowMouseMove';
|
|
4
5
|
import { useMouseDownHandlers } from '../../hooks/useMouseDownHandlers';
|
|
5
6
|
import { useOnScroll } from '../../hooks/useOnScroll';
|
|
@@ -17,7 +18,7 @@ export function Body() {
|
|
|
17
18
|
useOnMouseMove();
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
|
-
<div className=
|
|
21
|
+
<div className={ClassNames.scrollBody} ref={BodyRef}>
|
|
21
22
|
<EmojiVariationPicker />
|
|
22
23
|
<EmojiList />
|
|
23
24
|
</div>
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '../../dataUtils/emojiSelectors';
|
|
14
14
|
import { parseNativeEmoji } from '../../dataUtils/parseNativeEmoji';
|
|
15
15
|
import { EmojiStyle } from '../../types/exposedTypes';
|
|
16
|
+
import { Button } from '../atoms/Button';
|
|
16
17
|
import { useEmojisThatFailedToLoadState } from '../context/PickerContext';
|
|
17
18
|
import './Emoji.css';
|
|
18
19
|
|
|
@@ -46,7 +47,7 @@ export function ClickableEmoji({
|
|
|
46
47
|
const hasVariations = emojiHasVariations(emoji);
|
|
47
48
|
|
|
48
49
|
return (
|
|
49
|
-
<
|
|
50
|
+
<Button
|
|
50
51
|
className={clsx(ClassNames.emoji, {
|
|
51
52
|
[ClassNames.hidden]: hidden,
|
|
52
53
|
[ClassNames.hiddenOnSearch]: hiddenOnSearch,
|
|
@@ -57,7 +58,6 @@ export function ClickableEmoji({
|
|
|
57
58
|
// @ts-ignore - let's ignore the fact this is not a real react ref, ok?
|
|
58
59
|
aria-label={emojiName(emoji)}
|
|
59
60
|
data-full-name={emojiNames(emoji)}
|
|
60
|
-
type="button"
|
|
61
61
|
>
|
|
62
62
|
<ViewOnlyEmoji
|
|
63
63
|
unified={unified}
|
|
@@ -66,7 +66,7 @@ export function ClickableEmoji({
|
|
|
66
66
|
emojiStyle={emojiStyle}
|
|
67
67
|
lazyLoad={lazyLoad}
|
|
68
68
|
/>
|
|
69
|
-
</
|
|
69
|
+
</Button>
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -16,31 +16,59 @@
|
|
|
16
16
|
width: 100%;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.EmojiPickerReact
|
|
19
|
+
.EmojiPickerReact
|
|
20
|
+
.epr-search-container
|
|
21
|
+
button.epr-btn-clear-search
|
|
22
|
+
.epr-icn-clear-search {
|
|
20
23
|
background-image: svg-load(./svg/times.svg);
|
|
21
|
-
height: 20px;
|
|
22
|
-
width: 20px;
|
|
23
24
|
background-color: transparent;
|
|
24
25
|
background-repeat: no-repeat;
|
|
26
|
+
background-size: 20px;
|
|
27
|
+
height: 20px;
|
|
28
|
+
width: 20px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.EmojiPickerReact .epr-search-container button.epr-btn-clear-search {
|
|
25
32
|
position: absolute;
|
|
26
|
-
top: 50%;
|
|
27
33
|
right: var(--epr-search-bar-inner-padding);
|
|
34
|
+
height: 30px;
|
|
35
|
+
width: 30px;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
top: 50%;
|
|
28
40
|
transform: translateY(-50%);
|
|
29
|
-
|
|
41
|
+
padding: 0;
|
|
42
|
+
border-radius: 50%;
|
|
30
43
|
}
|
|
31
|
-
|
|
44
|
+
|
|
45
|
+
.EmojiPickerReact
|
|
46
|
+
.epr-search-container
|
|
47
|
+
button.epr-btn-clear-search:hover
|
|
48
|
+
.epr-icn-clear-search,
|
|
49
|
+
.EmojiPickerReact
|
|
50
|
+
.epr-search-container
|
|
51
|
+
button.epr-btn-clear-search:focus
|
|
52
|
+
.epr-icn-clear-search {
|
|
32
53
|
background-position-y: -20px;
|
|
33
54
|
}
|
|
34
55
|
|
|
56
|
+
.EmojiPickerReact .epr-search-container button.epr-btn-clear-search:hover,
|
|
57
|
+
.EmojiPickerReact .epr-search-container button.epr-btn-clear-search:focus {
|
|
58
|
+
background: var(--epr-hover-bg-color);
|
|
59
|
+
}
|
|
60
|
+
|
|
35
61
|
.EmojiPickerReact..epr-dark-theme
|
|
36
62
|
.epr-search-container
|
|
37
|
-
button.epr-btn-clear-search
|
|
63
|
+
button.epr-btn-clear-search
|
|
64
|
+
.epr-icn-clear-search {
|
|
38
65
|
background-position-y: -40px;
|
|
39
66
|
}
|
|
40
67
|
|
|
41
68
|
.EmojiPickerReact..epr-dark-theme
|
|
42
69
|
.epr-search-container
|
|
43
|
-
button.epr-btn-clear-search:hover
|
|
70
|
+
button.epr-btn-clear-search:hover
|
|
71
|
+
.epr-icn-clear-search {
|
|
44
72
|
background-position-y: -60px;
|
|
45
73
|
}
|
|
46
74
|
|
|
@@ -7,8 +7,13 @@ import {
|
|
|
7
7
|
useSearchPlaceHolderConfig
|
|
8
8
|
} from '../../config/useConfig';
|
|
9
9
|
import { useCloseAllOpenToggles } from '../../hooks/useCloseAllOpenToggles';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getNormalizedSearchTerm,
|
|
12
|
+
useClearSearch,
|
|
13
|
+
useFilter
|
|
14
|
+
} from '../../hooks/useFilter';
|
|
11
15
|
import Relative from '../Layout/Relative';
|
|
16
|
+
import { Button } from '../atoms/Button';
|
|
12
17
|
import { useSearchInputRef } from '../context/ElementRefContext';
|
|
13
18
|
|
|
14
19
|
import './Search.css';
|
|
@@ -45,11 +50,12 @@ export function Search() {
|
|
|
45
50
|
ref={SearchInputRef}
|
|
46
51
|
/>
|
|
47
52
|
<div className="epr-icn-search" />
|
|
48
|
-
<
|
|
53
|
+
<Button
|
|
49
54
|
className={clsx('epr-btn-clear-search', 'epr-visible-on-search-only')}
|
|
50
55
|
onClick={clearSearch}
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
>
|
|
57
|
+
<div className="epr-icn-clear-search" />
|
|
58
|
+
</Button>
|
|
53
59
|
</Relative>
|
|
54
60
|
);
|
|
55
61
|
}
|
|
@@ -57,7 +63,9 @@ export function Search() {
|
|
|
57
63
|
function CssSearch({ value }: { value: undefined | string }) {
|
|
58
64
|
return value ? (
|
|
59
65
|
<style>{`
|
|
60
|
-
.EmojiPickerReact button.epr-emoji:not([data-full-name*="${
|
|
66
|
+
.EmojiPickerReact button.epr-emoji:not([data-full-name*="${getNormalizedSearchTerm(
|
|
67
|
+
value
|
|
68
|
+
)}"]) {
|
|
61
69
|
display: none;
|
|
62
70
|
}
|
|
63
71
|
`}</style>
|
|
@@ -10,6 +10,7 @@ import { useCloseAllOpenToggles } from '../../hooks/useCloseAllOpenToggles';
|
|
|
10
10
|
import { useFocusSearchInput } from '../../hooks/useFocus';
|
|
11
11
|
import { SkinTones } from '../../types/exposedTypes';
|
|
12
12
|
import Relative from '../Layout/Relative';
|
|
13
|
+
import { Button } from '../atoms/Button';
|
|
13
14
|
import { useSkinTonePickerRef } from '../context/ElementRefContext';
|
|
14
15
|
import {
|
|
15
16
|
useActiveSkinToneState,
|
|
@@ -39,8 +40,7 @@ export function SkinTonePicker() {
|
|
|
39
40
|
{skinToneVariations.map((skinToneVariation, i) => {
|
|
40
41
|
const active = skinToneVariation === activeSkinTone;
|
|
41
42
|
return (
|
|
42
|
-
<
|
|
43
|
-
type="button"
|
|
43
|
+
<Button
|
|
44
44
|
style={{
|
|
45
45
|
transform: clsx(
|
|
46
46
|
`translateX(-${i * (isOpen ? 28 : 0)}px)`,
|
|
@@ -65,7 +65,7 @@ export function SkinTonePicker() {
|
|
|
65
65
|
aria-label={`Skin tone ${
|
|
66
66
|
skinTonesNamed[skinToneVariation as SkinTones]
|
|
67
67
|
}`}
|
|
68
|
-
></
|
|
68
|
+
></Button>
|
|
69
69
|
);
|
|
70
70
|
})}
|
|
71
71
|
</div>
|
|
@@ -10,13 +10,16 @@ import {
|
|
|
10
10
|
} from '../../config/categoryConfig';
|
|
11
11
|
import { useCategoriesConfig } from '../../config/useConfig';
|
|
12
12
|
import { useActiveCategoryScrollDetection } from '../../hooks/useActiveCategoryScrollDetection';
|
|
13
|
+
import useIsSearchMode from '../../hooks/useIsSearchMode';
|
|
13
14
|
import { useScrollCategoryIntoView } from '../../hooks/useScrollCategoryIntoView';
|
|
15
|
+
import { Button } from '../atoms/Button';
|
|
14
16
|
import { useCategoryNavigationRef } from '../context/ElementRefContext';
|
|
15
17
|
|
|
16
18
|
export function CategoryNavigation() {
|
|
17
19
|
const [activeCategory, setActiveCategory] = useState<string | null>(null);
|
|
18
20
|
const scrollCategoryIntoView = useScrollCategoryIntoView();
|
|
19
21
|
useActiveCategoryScrollDetection(setActiveCategory);
|
|
22
|
+
const isSearchMode = useIsSearchMode();
|
|
20
23
|
|
|
21
24
|
const categoriesConfig = useCategoriesConfig();
|
|
22
25
|
const CategoryNavigationRef = useCategoryNavigationRef();
|
|
@@ -26,8 +29,8 @@ export function CategoryNavigation() {
|
|
|
26
29
|
{categoriesConfig.map(categoryConfig => {
|
|
27
30
|
const category = categoryFromCategoryConfig(categoryConfig);
|
|
28
31
|
return (
|
|
29
|
-
<
|
|
30
|
-
|
|
32
|
+
<Button
|
|
33
|
+
tabIndex={isSearchMode ? -1 : 0}
|
|
31
34
|
className={clsx('epr-cat-btn', `epr-icn-${category}`, {
|
|
32
35
|
[ClassNames.active]: category === activeCategory
|
|
33
36
|
})}
|
package/src/config/config.ts
CHANGED
|
@@ -40,6 +40,7 @@ export function basePickerConfig(): PickerConfigInternal {
|
|
|
40
40
|
categories: baseCategoriesConfig(),
|
|
41
41
|
defaultSkinTone: SkinTones.NEUTRAL,
|
|
42
42
|
emojiStyle: EmojiStyle.APPLE,
|
|
43
|
+
height: 450,
|
|
43
44
|
lazyLoadEmojis: false,
|
|
44
45
|
onEmojiClick: function defaultOnClickHandler(
|
|
45
46
|
// @ts-ignore
|
|
@@ -49,15 +50,14 @@ export function basePickerConfig(): PickerConfigInternal {
|
|
|
49
50
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
50
51
|
event: MouseEvent
|
|
51
52
|
) {},
|
|
52
|
-
height: 450,
|
|
53
|
-
width: 350,
|
|
54
53
|
previewConfig: {
|
|
55
54
|
...basePreviewConfig
|
|
56
55
|
},
|
|
57
56
|
searchPlaceHolder: 'Search',
|
|
58
57
|
skinTonesDisabled: false,
|
|
59
58
|
suggestedEmojisMode: SuggestionMode.FREQUENT,
|
|
60
|
-
theme: Theme.LIGHT
|
|
59
|
+
theme: Theme.LIGHT,
|
|
60
|
+
width: 350
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
package/src/hooks/useFilter.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
12
12
|
import { emojiNames } from '../dataUtils/emojiSelectors';
|
|
13
13
|
|
|
14
|
+
import { useFocusSearchInput } from './useFocus';
|
|
15
|
+
|
|
14
16
|
function useSetFilterRef() {
|
|
15
17
|
const filterRef = useFilterRef();
|
|
16
18
|
|
|
@@ -28,6 +30,7 @@ function useSetFilterRef() {
|
|
|
28
30
|
export function useClearSearch() {
|
|
29
31
|
const applySearch = useApplySearch();
|
|
30
32
|
const SearchInputRef = useSearchInputRef();
|
|
33
|
+
const focusSearchInput = useFocusSearchInput();
|
|
31
34
|
|
|
32
35
|
return function clearSearch() {
|
|
33
36
|
if (SearchInputRef.current) {
|
|
@@ -35,6 +38,7 @@ export function useClearSearch() {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
applySearch('');
|
|
41
|
+
focusSearchInput();
|
|
38
42
|
};
|
|
39
43
|
}
|
|
40
44
|
|
|
@@ -44,10 +48,10 @@ export function useAppendSearch() {
|
|
|
44
48
|
|
|
45
49
|
return function appendSearch(str: string) {
|
|
46
50
|
if (SearchInputRef.current) {
|
|
47
|
-
SearchInputRef.current.value = SearchInputRef.current.value
|
|
48
|
-
applySearch(SearchInputRef.current.value);
|
|
51
|
+
SearchInputRef.current.value = `${SearchInputRef.current.value}${str}`;
|
|
52
|
+
applySearch(getNormalizedSearchTerm(SearchInputRef.current.value));
|
|
49
53
|
} else {
|
|
50
|
-
applySearch(str);
|
|
54
|
+
applySearch(getNormalizedSearchTerm(str));
|
|
51
55
|
}
|
|
52
56
|
};
|
|
53
57
|
}
|
|
@@ -66,9 +70,11 @@ export function useFilter() {
|
|
|
66
70
|
SearchInputRef
|
|
67
71
|
};
|
|
68
72
|
|
|
69
|
-
function onChange(
|
|
73
|
+
function onChange(inputValue: string) {
|
|
70
74
|
const filter = filterRef.current;
|
|
71
75
|
|
|
76
|
+
const nextValue = inputValue.toLowerCase();
|
|
77
|
+
|
|
72
78
|
if (filter?.[nextValue] || nextValue.length <= 1) {
|
|
73
79
|
return applySearch(nextValue);
|
|
74
80
|
}
|
|
@@ -96,9 +102,11 @@ function useApplySearch() {
|
|
|
96
102
|
|
|
97
103
|
return function applySearch(searchTerm: string) {
|
|
98
104
|
requestAnimationFrame(() => {
|
|
99
|
-
setSearchTerm(searchTerm
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
setSearchTerm(searchTerm ? searchTerm?.toLowerCase() : searchTerm).then(
|
|
106
|
+
() => {
|
|
107
|
+
scrollTo(PickerMainRef.current, 0);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
102
110
|
});
|
|
103
111
|
};
|
|
104
112
|
}
|
|
@@ -128,8 +136,7 @@ export function useIsEmojiFiltered(): (unified: string) => boolean {
|
|
|
128
136
|
const { current: filter } = useFilterRef();
|
|
129
137
|
const [searchTerm] = useSearchTermState();
|
|
130
138
|
|
|
131
|
-
return unified =>
|
|
132
|
-
isEmojiFilteredBySearchTerm(unified, filter, searchTerm.toLowerCase());
|
|
139
|
+
return unified => isEmojiFilteredBySearchTerm(unified, filter, searchTerm);
|
|
133
140
|
}
|
|
134
141
|
|
|
135
142
|
function isEmojiFilteredBySearchTerm(
|
|
@@ -168,3 +175,11 @@ function findLongestMatch(
|
|
|
168
175
|
|
|
169
176
|
return null;
|
|
170
177
|
}
|
|
178
|
+
|
|
179
|
+
export function getNormalizedSearchTerm(str: string): string {
|
|
180
|
+
if (!str || typeof str !== 'string') {
|
|
181
|
+
return '';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return str.trim().toLowerCase();
|
|
185
|
+
}
|
|
@@ -73,13 +73,8 @@ function usePickerMainKeyboardEvents() {
|
|
|
73
73
|
function onKeyDown(event: KeyboardEvent) {
|
|
74
74
|
const { key } = event;
|
|
75
75
|
|
|
76
|
+
disallowMouseMove();
|
|
76
77
|
switch (key) {
|
|
77
|
-
case KeyboardEvents.ArrowDown:
|
|
78
|
-
case KeyboardEvents.ArrowUp:
|
|
79
|
-
case KeyboardEvents.ArrowLeft:
|
|
80
|
-
case KeyboardEvents.ArrowRight:
|
|
81
|
-
disallowMouseMove();
|
|
82
|
-
break;
|
|
83
78
|
// eslint-disable-next-line no-fallthrough
|
|
84
79
|
case KeyboardEvents.Escape:
|
|
85
80
|
event.preventDefault();
|