emoji-picker-react 4.5.7 → 4.5.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/README.md +1 -1
- package/dist/components/context/PickerConfigContext.d.ts +1 -0
- package/dist/config/config.d.ts +4 -0
- package/dist/config/useConfig.d.ts +1 -0
- package/dist/emoji-picker-react.cjs.development.css +2 -2
- package/dist/emoji-picker-react.cjs.development.js +73 -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 +76 -15
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/useFilter.d.ts +1 -0
- package/package.json +1 -1
- package/src/EmojiPickerReact.tsx +4 -1
- package/src/components/body/EmojiCategory.css +2 -0
- package/src/components/body/EmojiCategory.tsx +1 -1
- package/src/components/context/PickerConfigContext.tsx +18 -1
- package/src/components/header/Search.css +10 -0
- package/src/components/header/Search.tsx +13 -1
- package/src/components/navigation/CategoryNavigation.tsx +13 -3
- package/src/config/config.ts +7 -0
- package/src/config/useConfig.ts +16 -0
- package/src/hooks/useFilter.ts +10 -0
|
@@ -5,6 +5,7 @@ export declare function useFilter(): {
|
|
|
5
5
|
onChange: (inputValue: string) => void;
|
|
6
6
|
searchTerm: string;
|
|
7
7
|
SearchInputRef: import("../components/context/ElementRefContext").ElementRef<HTMLInputElement>;
|
|
8
|
+
statusSearchResults: string;
|
|
8
9
|
};
|
|
9
10
|
export declare function useIsEmojiFiltered(): (unified: string) => boolean;
|
|
10
11
|
export declare type FilterDict = Record<string, DataEmoji>;
|
package/package.json
CHANGED
package/src/EmojiPickerReact.tsx
CHANGED
|
@@ -26,6 +26,8 @@ function EmojiPicker(props: PickerProps) {
|
|
|
26
26
|
|
|
27
27
|
// eslint-disable-next-line complexity
|
|
28
28
|
export default React.memo(EmojiPicker, (prev, next) => {
|
|
29
|
+
const prevCustomEmojis = prev.customEmojis ?? [];
|
|
30
|
+
const nextCustomEmojis = next.customEmojis ?? [];
|
|
29
31
|
return (
|
|
30
32
|
prev.emojiVersion === next.emojiVersion &&
|
|
31
33
|
prev.searchPlaceHolder === next.searchPlaceHolder &&
|
|
@@ -40,6 +42,7 @@ export default React.memo(EmojiPicker, (prev, next) => {
|
|
|
40
42
|
prev.height === next.height &&
|
|
41
43
|
prev.width === next.width &&
|
|
42
44
|
prev.searchDisabled === next.searchDisabled &&
|
|
43
|
-
prev.skinTonePickerLocation === next.skinTonePickerLocation
|
|
45
|
+
prev.skinTonePickerLocation === next.skinTonePickerLocation &&
|
|
46
|
+
prevCustomEmojis.length === nextCustomEmojis.length
|
|
44
47
|
);
|
|
45
48
|
});
|
|
@@ -33,7 +33,7 @@ export function EmojiCategory({
|
|
|
33
33
|
data-name={category}
|
|
34
34
|
aria-label={categoryName}
|
|
35
35
|
>
|
|
36
|
-
<
|
|
36
|
+
<h2 className={ClassNames.label}>{categoryName}</h2>
|
|
37
37
|
<div className={ClassNames.categoryContent}>{children}</div>
|
|
38
38
|
</li>
|
|
39
39
|
);
|
|
@@ -17,7 +17,8 @@ const ConfigContext = React.createContext<PickerConfigInternal>(
|
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
export function PickerConfigProvider({ children, ...config }: Props) {
|
|
20
|
-
const
|
|
20
|
+
const mergedConfig = useSetConfig(config);
|
|
21
|
+
|
|
21
22
|
return (
|
|
22
23
|
<ConfigContext.Provider value={mergedConfig}>
|
|
23
24
|
{children}
|
|
@@ -25,6 +26,22 @@ export function PickerConfigProvider({ children, ...config }: Props) {
|
|
|
25
26
|
);
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
export function useSetConfig(config: PickerConfig) {
|
|
30
|
+
const [mergedConfig, setMergedConfig] = React.useState(() =>
|
|
31
|
+
mergeConfig(config)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
if (config.customEmojis?.length !== mergedConfig.customEmojis?.length) {
|
|
36
|
+
setMergedConfig(mergeConfig(config));
|
|
37
|
+
}
|
|
38
|
+
// not gonna...
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, [config.customEmojis?.length]);
|
|
41
|
+
|
|
42
|
+
return mergedConfig;
|
|
43
|
+
}
|
|
44
|
+
|
|
28
45
|
export function usePickerConfig() {
|
|
29
46
|
return React.useContext(ConfigContext);
|
|
30
47
|
}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
min-width: 0;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
.EmojiPickerReact .epr-search-container .epr-status-visually-hidden {
|
|
8
|
+
clip: rect(0 0 0 0);
|
|
9
|
+
clip-path: inset(50%);
|
|
10
|
+
height: 1px;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
position: absolute;
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
width: 1px;
|
|
15
|
+
}
|
|
16
|
+
|
|
7
17
|
.EmojiPickerReact .epr-search-container input.epr-search {
|
|
8
18
|
outline: none;
|
|
9
19
|
transition: all 0.2s ease-in-out;
|
|
@@ -47,7 +47,7 @@ export function Search() {
|
|
|
47
47
|
const clearSearch = useClearSearch();
|
|
48
48
|
const placeholder = useSearchPlaceHolderConfig();
|
|
49
49
|
const autoFocus = useAutoFocusSearchConfig();
|
|
50
|
-
const { onChange } = useFilter();
|
|
50
|
+
const { statusSearchResults, searchTerm, onChange } = useFilter();
|
|
51
51
|
|
|
52
52
|
const input = SearchInputRef?.current;
|
|
53
53
|
const value = input?.value;
|
|
@@ -62,6 +62,7 @@ export function Search() {
|
|
|
62
62
|
onFocus={closeAllOpenToggles}
|
|
63
63
|
className="epr-search"
|
|
64
64
|
type="text"
|
|
65
|
+
aria-controls='epr-search-id'
|
|
65
66
|
placeholder={placeholder}
|
|
66
67
|
onChange={event => {
|
|
67
68
|
setInc(inc + 1);
|
|
@@ -71,6 +72,17 @@ export function Search() {
|
|
|
71
72
|
}}
|
|
72
73
|
ref={SearchInputRef}
|
|
73
74
|
/>
|
|
75
|
+
{searchTerm ? (
|
|
76
|
+
<div
|
|
77
|
+
role='status'
|
|
78
|
+
className={clsx('epr-status-search-results', 'epr-status-visually-hidden')}
|
|
79
|
+
aria-live='polite'
|
|
80
|
+
id='epr-search-id'
|
|
81
|
+
aria-atomic='true'
|
|
82
|
+
>
|
|
83
|
+
{statusSearchResults}
|
|
84
|
+
</div>
|
|
85
|
+
) : null}
|
|
74
86
|
<div className="epr-icn-search" />
|
|
75
87
|
<Button
|
|
76
88
|
className={clsx('epr-btn-clear-search', 'epr-visible-on-search-only')}
|
|
@@ -27,9 +27,16 @@ export function CategoryNavigation() {
|
|
|
27
27
|
const hideCustomCategory = useShouldHideCustomEmojis();
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
|
-
|
|
30
|
+
<div
|
|
31
|
+
className='epr-category-nav'
|
|
32
|
+
role='tablist'
|
|
33
|
+
aria-label='Category navigation'
|
|
34
|
+
id='epr-category-nav-id'
|
|
35
|
+
ref={CategoryNavigationRef}
|
|
36
|
+
>
|
|
31
37
|
{categoriesConfig.map(categoryConfig => {
|
|
32
38
|
const category = categoryFromCategoryConfig(categoryConfig);
|
|
39
|
+
const isActiveCategory = category === activeCategory;
|
|
33
40
|
|
|
34
41
|
if (isCustomCategory(categoryConfig) && hideCustomCategory) {
|
|
35
42
|
return null;
|
|
@@ -37,9 +44,9 @@ export function CategoryNavigation() {
|
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
<Button
|
|
40
|
-
tabIndex={isSearchMode ? -1 : 0}
|
|
47
|
+
tabIndex={(isSearchMode || isActiveCategory) ? -1 : 0}
|
|
41
48
|
className={clsx('epr-cat-btn', `epr-icn-${category}`, {
|
|
42
|
-
[ClassNames.active]:
|
|
49
|
+
[ClassNames.active]: isActiveCategory
|
|
43
50
|
})}
|
|
44
51
|
key={category}
|
|
45
52
|
onClick={() => {
|
|
@@ -47,6 +54,9 @@ export function CategoryNavigation() {
|
|
|
47
54
|
scrollCategoryIntoView(category);
|
|
48
55
|
}}
|
|
49
56
|
aria-label={categoryNameFromCategoryConfig(categoryConfig)}
|
|
57
|
+
aria-selected={isActiveCategory}
|
|
58
|
+
role='tab'
|
|
59
|
+
aria-controls='epr-category-nav-id'
|
|
50
60
|
/>
|
|
51
61
|
);
|
|
52
62
|
})}
|
package/src/config/config.ts
CHANGED
|
@@ -22,6 +22,13 @@ import { CustomEmoji } from './customEmojiConfig';
|
|
|
22
22
|
const KNOWN_FAILING_EMOJIS = ['2640-fe0f', '2642-fe0f', '2695-fe0f'];
|
|
23
23
|
|
|
24
24
|
export const DEFAULT_SEARCH_PLACEHOLDER = 'Search';
|
|
25
|
+
export const SEARCH_RESULTS_NO_RESULTS_FOUND = 'No results found';
|
|
26
|
+
export const SEARCH_RESULTS_SUFFIX =
|
|
27
|
+
' found. Use up and down arrow keys to navigate.';
|
|
28
|
+
export const SEARCH_RESULTS_ONE_RESULT_FOUND =
|
|
29
|
+
'1 result' + SEARCH_RESULTS_SUFFIX;
|
|
30
|
+
export const SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND =
|
|
31
|
+
'%n results' + SEARCH_RESULTS_SUFFIX;
|
|
25
32
|
|
|
26
33
|
export function mergeConfig(
|
|
27
34
|
userConfig: PickerConfig = {}
|
package/src/config/useConfig.ts
CHANGED
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
import { CategoriesConfig } from './categoryConfig';
|
|
12
12
|
import {
|
|
13
13
|
DEFAULT_SEARCH_PLACEHOLDER,
|
|
14
|
+
SEARCH_RESULTS_NO_RESULTS_FOUND,
|
|
15
|
+
SEARCH_RESULTS_ONE_RESULT_FOUND,
|
|
16
|
+
SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND,
|
|
14
17
|
PickerDimensions,
|
|
15
18
|
PreviewConfig
|
|
16
19
|
} from './config';
|
|
@@ -126,3 +129,16 @@ function getDimension(dimensionConfig: PickerDimensions): PickerDimensions {
|
|
|
126
129
|
? `${dimensionConfig}px`
|
|
127
130
|
: dimensionConfig;
|
|
128
131
|
}
|
|
132
|
+
|
|
133
|
+
export function useSearchResultsConfig(searchResultsCount: number): string {
|
|
134
|
+
const hasResults = searchResultsCount > 0;
|
|
135
|
+
const isPlural = searchResultsCount > 1;
|
|
136
|
+
|
|
137
|
+
if (hasResults) {
|
|
138
|
+
return isPlural ?
|
|
139
|
+
SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND.replace('%n', searchResultsCount.toString())
|
|
140
|
+
: SEARCH_RESULTS_ONE_RESULT_FOUND;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return SEARCH_RESULTS_NO_RESULTS_FOUND;
|
|
144
|
+
}
|
package/src/hooks/useFilter.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { DataEmoji } from '../dataUtils/DataTypes';
|
|
|
12
12
|
import { emojiNames } from '../dataUtils/emojiSelectors';
|
|
13
13
|
|
|
14
14
|
import { useFocusSearchInput } from './useFocus';
|
|
15
|
+
import { useSearchResultsConfig } from '../config/useConfig';
|
|
15
16
|
|
|
16
17
|
function useSetFilterRef() {
|
|
17
18
|
const filterRef = useFilterRef();
|
|
@@ -63,11 +64,13 @@ export function useFilter() {
|
|
|
63
64
|
const applySearch = useApplySearch();
|
|
64
65
|
|
|
65
66
|
const [searchTerm] = useSearchTermState();
|
|
67
|
+
const statusSearchResults = getStatusSearchResults(filterRef.current, searchTerm);
|
|
66
68
|
|
|
67
69
|
return {
|
|
68
70
|
onChange,
|
|
69
71
|
searchTerm,
|
|
70
72
|
SearchInputRef,
|
|
73
|
+
statusSearchResults,
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
function onChange(inputValue: string) {
|
|
@@ -183,3 +186,10 @@ export function getNormalizedSearchTerm(str: string): string {
|
|
|
183
186
|
|
|
184
187
|
return str.trim().toLowerCase();
|
|
185
188
|
}
|
|
189
|
+
|
|
190
|
+
function getStatusSearchResults(filterState: FilterState, searchTerm: string): string {
|
|
191
|
+
if (!filterState?.[searchTerm]) return '';
|
|
192
|
+
|
|
193
|
+
const searchResultsCount = Object.entries(filterState?.[searchTerm])?.length || 0;
|
|
194
|
+
return useSearchResultsConfig(searchResultsCount);
|
|
195
|
+
}
|