emoji-picker-react 4.5.6 → 4.5.8

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.
@@ -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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.5.6",
2
+ "version": "4.5.8",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -1,7 +1,7 @@
1
1
  import { DataEmoji } from '../dataUtils/DataTypes';
2
2
  import {
3
3
  emojiByUnified,
4
- unifiedWithoutSkinTone,
4
+ unifiedWithoutSkinTone
5
5
  } from '../dataUtils/emojiSelectors';
6
6
 
7
7
  import { asSelectors, ClassNames } from './classNames';
@@ -13,7 +13,7 @@ export const EmojiButtonSelector = `button${asSelectors(ClassNames.emoji)}`;
13
13
  export const VisibleEmojiSelector = [
14
14
  EmojiButtonSelector,
15
15
  asSelectors(ClassNames.visible),
16
- `:not(${asSelectors(ClassNames.hidden)})`,
16
+ `:not(${asSelectors(ClassNames.hidden)})`
17
17
  ].join('');
18
18
 
19
19
  export function buttonFromTarget(
@@ -40,7 +40,7 @@ export function emojiFromElement(
40
40
  return [];
41
41
  }
42
42
 
43
- const emoji = emojiByUnified(originalUnified);
43
+ const emoji = emojiByUnified(unified ?? originalUnified);
44
44
 
45
45
  if (!emoji) {
46
46
  return [];
@@ -18,6 +18,8 @@
18
18
  display: flex;
19
19
  align-items: center;
20
20
  font-weight: bold;
21
+ font-size: 16px;
22
+ margin: 0;
21
23
  text-transform: capitalize;
22
24
  backdrop-filter: blur(3px);
23
25
  padding: var(--epr-category-label-padding);
@@ -33,7 +33,7 @@ export function EmojiCategory({
33
33
  data-name={category}
34
34
  aria-label={categoryName}
35
35
  >
36
- <div className={ClassNames.label}>{categoryName}</div>
36
+ <h2 className={ClassNames.label}>{categoryName}</h2>
37
37
  <div className={ClassNames.categoryContent}>{children}</div>
38
38
  </li>
39
39
  );
@@ -67,6 +67,10 @@
67
67
  letter-spacing: 0;
68
68
  }
69
69
 
70
+ .EmojiPickerReact button.epr-emoji > * {
71
+ transition: background-color 0.2s;
72
+ }
73
+
70
74
  .EmojiPickerReact button.epr-emoji:hover > * {
71
75
  background-color: var(--epr-emoji-hover-color);
72
76
  }
@@ -17,8 +17,8 @@ import Flex from '../Layout/Flex';
17
17
  import Space from '../Layout/Space';
18
18
  import { useEmojiVariationPickerState } from '../context/PickerContext';
19
19
  import './Preview.css';
20
- import { SkinTonePickerMenu } from '../header/SkinTonePicker';
21
20
  import { ViewOnlyEmoji } from '../emoji/ViewOnlyEmoji';
21
+ import { SkinTonePickerMenu } from '../header/SkinTonePicker';
22
22
 
23
23
  export function Preview() {
24
24
  const previewConfig = usePreviewConfig();
@@ -46,16 +46,19 @@ export function PreviewBody() {
46
46
 
47
47
  useEmojiPreviewEvents(previewConfig.showPreview, setPreviewEmoji);
48
48
 
49
- const emoji = emojiByUnified(previewEmoji?.originalUnified);
49
+ const emoji = emojiByUnified(
50
+ previewEmoji?.unified ?? previewEmoji?.originalUnified
51
+ );
50
52
 
51
53
  const show = emoji != null && previewEmoji != null;
52
54
 
53
55
  return <PreviewContent />;
54
56
 
55
57
  function PreviewContent() {
56
- const defaultEmoji = variationPickerEmoji ?? emojiByUnified(previewConfig.defaultEmoji)
58
+ const defaultEmoji =
59
+ variationPickerEmoji ?? emojiByUnified(previewConfig.defaultEmoji);
57
60
  if (!defaultEmoji) {
58
- return null
61
+ return null;
59
62
  }
60
63
  const defaultText = variationPickerEmoji
61
64
  ? emojiName(variationPickerEmoji)
@@ -83,9 +86,7 @@ export function PreviewBody() {
83
86
  ) : null}
84
87
  </div>
85
88
  {show ? (
86
- <div className="epr-preview-emoji-label">
87
- {emojiName(emoji)}
88
- </div>
89
+ <div className="epr-preview-emoji-label">{emojiName(emoji)}</div>
89
90
  ) : (
90
91
  <div className="epr-preview-emoji-label">{defaultText}</div>
91
92
  )}
@@ -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
- <div className="epr-category-nav" ref={CategoryNavigationRef}>
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]: category === activeCategory
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
  })}
@@ -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 = {}
@@ -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
+ }
@@ -123,6 +123,13 @@ const allEmojisByUnified: {
123
123
  setTimeout(() => {
124
124
  allEmojis.reduce((allEmojis, Emoji) => {
125
125
  allEmojis[emojiUnified(Emoji)] = Emoji;
126
+
127
+ if (emojiHasVariations(Emoji)) {
128
+ emojiVariations(Emoji).forEach(variation => {
129
+ allEmojis[variation] = Emoji;
130
+ });
131
+ }
132
+
126
133
  return allEmojis;
127
134
  }, allEmojisByUnified);
128
135
  });
@@ -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
+ }