emoji-picker-react 4.0.0-rc.8 → 4.0.0
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 +176 -43
- package/dist/DomUtils/classNames.d.ts +9 -1
- package/dist/DomUtils/elementPositionInRow.d.ts +10 -0
- package/dist/DomUtils/focusElement.d.ts +5 -0
- package/dist/DomUtils/getActiveElement.d.ts +2 -0
- package/dist/DomUtils/isDarkTheme.d.ts +1 -0
- package/dist/DomUtils/keyboardNavigation.d.ts +8 -0
- package/dist/DomUtils/scrollTo.d.ts +3 -1
- package/dist/DomUtils/selectors.d.ts +24 -11
- package/dist/EmojiPickerReact.d.ts +6 -0
- package/dist/components/ErrorBoundary.d.ts +15 -0
- package/dist/components/body/{RecentlyUsed.d.ts → Suggested.d.ts} +1 -1
- package/dist/components/context/ElementRefContext.d.ts +10 -13
- package/dist/components/context/PickerContext.d.ts +3 -3
- package/dist/components/emoji/Emoji.d.ts +11 -7
- package/dist/components/emoji/ExportedEmoji.d.ts +8 -0
- package/dist/components/footer/Preview.d.ts +1 -1
- package/dist/config/categoryConfig.d.ts +7 -3
- package/dist/config/config.d.ts +18 -15
- package/dist/config/useConfig.d.ts +11 -4
- package/dist/data/skinToneVariations.d.ts +2 -0
- package/dist/dataUtils/emojiSelectors.d.ts +3 -2
- package/dist/dataUtils/suggested.d.ts +11 -0
- package/dist/emoji-picker-react.cjs.development.css +9 -9
- package/dist/emoji-picker-react.cjs.development.js +3774 -3070
- 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 +3784 -3080
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/preloadEmoji.d.ts +1 -1
- package/dist/hooks/useActiveCategoryScrollDetection.d.ts +1 -2
- package/dist/hooks/useCloseAllOpenToggles.d.ts +2 -4
- package/dist/hooks/useDebouncedState.d.ts +1 -1
- package/dist/hooks/useDisallowMouseMove.d.ts +4 -0
- package/dist/hooks/useEmojiPreviewEvents.d.ts +3 -0
- package/dist/hooks/useFilter.d.ts +3 -3
- package/dist/hooks/useFocus.d.ts +3 -0
- package/dist/hooks/useInitialLoad.d.ts +1 -1
- package/dist/hooks/useIsEmojiHidden.d.ts +7 -1
- package/dist/hooks/useKeyboardNavigation.d.ts +1 -0
- package/dist/hooks/useMouseDownHandlers.d.ts +3 -2
- package/dist/hooks/useOnFocus.d.ts +1 -0
- package/dist/hooks/useScrollCategoryIntoView.d.ts +1 -0
- package/dist/hooks/useSetVariationPicker.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/types/exposedTypes.d.ts +5 -1
- package/package.json +13 -5
- package/src/DomUtils/classNames.ts +12 -1
- package/src/DomUtils/elementPositionInRow.ts +167 -0
- package/src/DomUtils/focusElement.ts +35 -0
- package/src/DomUtils/getActiveElement.ts +5 -0
- package/src/DomUtils/isDarkTheme.ts +7 -0
- package/src/DomUtils/keyboardNavigation.ts +161 -0
- package/src/DomUtils/scrollTo.ts +22 -1
- package/src/DomUtils/selectors.ts +200 -41
- package/src/EmojiPickerReact.css +99 -48
- package/src/EmojiPickerReact.tsx +26 -0
- package/src/components/ErrorBoundary.tsx +28 -0
- package/src/components/body/Body.tsx +3 -2
- package/src/components/body/EmojiCategory.css +14 -28
- package/src/components/body/EmojiCategory.tsx +5 -4
- package/src/components/body/EmojiList.tsx +13 -13
- package/src/components/body/EmojiVariationPicker.css +13 -5
- package/src/components/body/EmojiVariationPicker.tsx +25 -17
- package/src/components/body/Suggested.tsx +54 -0
- package/src/components/context/ElementRefContext.tsx +54 -19
- package/src/components/context/PickerContext.tsx +36 -33
- package/src/components/emoji/Emoji.css +42 -12
- package/src/components/emoji/Emoji.tsx +73 -34
- package/src/components/emoji/ExportedEmoji.tsx +30 -0
- package/src/components/footer/Preview.css +1 -1
- package/src/components/footer/Preview.tsx +16 -23
- package/src/components/header/Search.css +7 -7
- package/src/components/header/Search.tsx +31 -7
- package/src/components/header/SkinTonePicker.css +15 -8
- package/src/components/header/SkinTonePicker.tsx +23 -5
- package/src/components/main/PickerMain.css +0 -2
- package/src/components/main/PickerMain.tsx +14 -1
- package/src/components/navigation/CategoryNavigation.css +41 -10
- package/src/components/navigation/CategoryNavigation.tsx +22 -10
- package/src/components/navigation/svg/CategoryNav.svg +343 -379
- package/src/config/categoryConfig.ts +40 -14
- package/src/config/config.ts +59 -13
- package/src/config/useConfig.ts +35 -7
- package/src/data/emojis.json +1 -1
- package/src/data/skinToneVariations.ts +19 -0
- package/src/dataUtils/emojiSelectors.ts +25 -5
- package/src/dataUtils/{recentlyUsed.ts → suggested.ts} +20 -18
- package/src/hooks/preloadEmoji.ts +13 -2
- package/src/hooks/useActiveCategoryScrollDetection.ts +10 -8
- package/src/hooks/useCloseAllOpenToggles.ts +15 -4
- package/src/hooks/useDebouncedState.ts +10 -7
- package/src/hooks/useDisallowMouseMove.ts +47 -0
- package/src/hooks/useEmojiPreviewEvents.ts +103 -0
- package/src/hooks/useFilter.ts +46 -47
- package/src/hooks/useFocus.ts +40 -0
- package/src/hooks/useInitialLoad.ts +1 -0
- package/src/hooks/useIsEmojiHidden.ts +16 -3
- package/src/hooks/useKeyboardNavigation.ts +438 -0
- package/src/hooks/useMouseDownHandlers.ts +97 -89
- package/src/hooks/useOnFocus.ts +46 -0
- package/src/hooks/useOnScroll.ts +2 -2
- package/src/hooks/useScrollCategoryIntoView.ts +28 -0
- package/src/hooks/useSetVariationPicker.ts +28 -0
- package/src/index.tsx +9 -17
- package/src/types/exposedTypes.ts +6 -1
- package/dist/DomUtils/emojiElementRef.d.ts +0 -10
- package/dist/DomUtils/scrollCategoryIntoView.d.ts +0 -1
- package/dist/dataUtils/recentlyUsed.d.ts +0 -11
- package/dist/hooks/useEmojiElements.d.ts +0 -1
- package/dist/hooks/useEmojiMouseEnter.d.ts +0 -3
- package/src/DomUtils/emojiElementRef.ts +0 -42
- package/src/DomUtils/scrollCategoryIntoView.ts +0 -18
- package/src/components/body/RecentlyUsed.tsx +0 -50
- package/src/hooks/useEmojiElements.ts +0 -7
- package/src/hooks/useEmojiMouseEnter.ts +0 -59
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
2
2
|
import { EmojiStyle } from '../types/exposedTypes';
|
|
3
|
-
export declare function preloadEmoji(emoji: DataEmoji, emojiStyle: EmojiStyle): void;
|
|
3
|
+
export declare function preloadEmoji(emoji: undefined | DataEmoji, emojiStyle: EmojiStyle): void;
|
|
4
4
|
export declare const preloadedEmojs: Set<string>;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function useActiveCategoryScrollDetection(bodyRef: ElementRef): void;
|
|
1
|
+
export declare function useActiveCategoryScrollDetection(setActiveCategory: (category: string) => void): void;
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export declare function useCloseAllOpenToggles():
|
|
2
|
-
|
|
3
|
-
dependencyArray: (boolean | import("../dataUtils/DataTypes").DataEmoji | null)[];
|
|
4
|
-
};
|
|
1
|
+
export declare function useCloseAllOpenToggles(): () => void;
|
|
2
|
+
export declare function useHasOpenToggles(): () => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function useDebouncedState<T>(initialValue: T, delay?: number): [T, (value: T) =>
|
|
1
|
+
export declare function useDebouncedState<T>(initialValue: T, delay?: number): [T, (value: T) => Promise<T>];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
1
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
2
|
+
export declare function useClearSearch(): () => void;
|
|
3
|
+
export declare function useAppendSearch(): (str: string) => void;
|
|
3
4
|
export declare function useFilter(): {
|
|
4
5
|
onChange: (nextValue: string) => void;
|
|
5
6
|
searchTerm: string;
|
|
6
|
-
|
|
7
|
-
SearchInputRef: import("react").RefObject<HTMLInputElement>;
|
|
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>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
export declare function useMarkInitialLoad(dispatch: React.Dispatch<React.SetStateAction<boolean>>): void;
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { DataEmoji } from '../dataUtils/DataTypes';
|
|
2
|
-
export declare function useIsEmojiHidden(): (emoji: DataEmoji) =>
|
|
2
|
+
export declare function useIsEmojiHidden(): (emoji: DataEmoji) => IsHiddenReturn;
|
|
3
|
+
declare type IsHiddenReturn = {
|
|
4
|
+
failedToLoad: boolean;
|
|
5
|
+
filteredOut: boolean;
|
|
6
|
+
hidden: boolean;
|
|
7
|
+
};
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useKeyboardNavigation(): void;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { NullableElement } from '../DomUtils/selectors';
|
|
3
|
+
export declare function useMouseDownHandlers(BodyRef: React.MutableRefObject<NullableElement>): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useOnFocus(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useScrollCategoryIntoView(): (category: string) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { PickerConfig } from './config/config';
|
|
3
|
-
|
|
3
|
+
export { ExportedEmoji as Emoji } from './components/emoji/ExportedEmoji';
|
|
4
4
|
export { EmojiStyle, SkinTones, Theme, Categories, EmojiClickData } from './types/exposedTypes';
|
|
5
5
|
export interface Props extends PickerConfig {
|
|
6
6
|
}
|
|
7
|
-
export
|
|
7
|
+
export default function EmojiPicker(props: Props): JSX.Element;
|
|
@@ -6,6 +6,10 @@ export declare type EmojiClickData = {
|
|
|
6
6
|
names: string[];
|
|
7
7
|
getImageUrl: (emojiStyle: EmojiStyle) => string;
|
|
8
8
|
};
|
|
9
|
+
export declare enum SuggestionMode {
|
|
10
|
+
RECENT = "recent",
|
|
11
|
+
FREQUENT = "frequent"
|
|
12
|
+
}
|
|
9
13
|
export declare enum EmojiStyle {
|
|
10
14
|
NATIVE = "native",
|
|
11
15
|
APPLE = "apple",
|
|
@@ -27,7 +31,7 @@ export declare enum SkinTones {
|
|
|
27
31
|
DARK = "1f3ff"
|
|
28
32
|
}
|
|
29
33
|
export declare enum Categories {
|
|
30
|
-
|
|
34
|
+
SUGGESTED = "suggested",
|
|
31
35
|
SMILEYS_PEOPLE = "smileys_people",
|
|
32
36
|
ANIMALS_NATURE = "animals_nature",
|
|
33
37
|
FOOD_DRINK = "food_drink",
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0
|
|
2
|
+
"version": "4.0.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=10"
|
|
12
12
|
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/ealush/emoji-picker-react.git"
|
|
16
|
+
},
|
|
13
17
|
"scripts": {
|
|
14
18
|
"start": "tsdx watch",
|
|
15
19
|
"build": "node ./scripts/prepare.js && tsdx build",
|
|
16
20
|
"test": "tsdx test --passWithNoTests",
|
|
17
|
-
"lint": "
|
|
21
|
+
"lint": "eslint ./src --ext .ts,.tsx",
|
|
18
22
|
"prepare": "tsdx build",
|
|
19
23
|
"size": "size-limit",
|
|
20
24
|
"analyze": "size-limit --why",
|
|
@@ -26,7 +30,7 @@
|
|
|
26
30
|
},
|
|
27
31
|
"husky": {
|
|
28
32
|
"hooks": {
|
|
29
|
-
"pre-commit": "
|
|
33
|
+
"pre-commit": "yarn lint"
|
|
30
34
|
}
|
|
31
35
|
},
|
|
32
36
|
"prettier": {
|
|
@@ -58,6 +62,8 @@
|
|
|
58
62
|
"@storybook/react": "^6.5.10",
|
|
59
63
|
"@types/react": "^18.0.17",
|
|
60
64
|
"@types/react-dom": "^18.0.6",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.36.2",
|
|
66
|
+
"@typescript-eslint/parser": "^5.36.2",
|
|
61
67
|
"autoprefixer": "^10.4.8",
|
|
62
68
|
"babel-loader": "^8.2.5",
|
|
63
69
|
"cssnano": "^5.1.13",
|
|
@@ -77,12 +83,14 @@
|
|
|
77
83
|
"rollup-plugin-postcss": "^4.0.2",
|
|
78
84
|
"size-limit": "^8.0.1",
|
|
79
85
|
"tiny-invariant": "^1.2.0",
|
|
80
|
-
"tinykeys": "^1.4.0",
|
|
81
86
|
"tsdx": "^0.14.1",
|
|
82
87
|
"tslib": "^2.4.0",
|
|
83
88
|
"typescript": "^4.7.4"
|
|
84
89
|
},
|
|
85
90
|
"dependencies": {
|
|
86
|
-
"clsx": "^1.2.1"
|
|
91
|
+
"clsx": "^1.2.1",
|
|
92
|
+
"eslint-plugin-jsx-a11y": "^6.6.1",
|
|
93
|
+
"eslint-plugin-react": "^7.31.8",
|
|
94
|
+
"eslint-plugin-react-hooks": "^4.6.0"
|
|
87
95
|
}
|
|
88
96
|
}
|
|
@@ -2,5 +2,16 @@ export enum ClassNames {
|
|
|
2
2
|
hiddenOnSearch = 'epr-hidden-on-search',
|
|
3
3
|
searchActive = 'epr-search-active',
|
|
4
4
|
hidden = 'epr-hidden',
|
|
5
|
-
visible = 'epr-visible'
|
|
5
|
+
visible = 'epr-visible',
|
|
6
|
+
active = 'epr-active',
|
|
7
|
+
emoji = 'epr-emoji',
|
|
8
|
+
category = 'epr-emoji-category',
|
|
9
|
+
label = 'epr-emoji-category-label',
|
|
10
|
+
categoryContent = 'epr-emoji-category-content',
|
|
11
|
+
emojiHasVariatios = 'epr-emoji-has-variations',
|
|
12
|
+
external = '__EmojiPicker__'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function asSelectors(...classNames: ClassNames[]): string {
|
|
16
|
+
return classNames.map(c => `.${c}`).join('');
|
|
6
17
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { NullableElement } from './selectors';
|
|
2
|
+
|
|
3
|
+
export function elementCountInRow(
|
|
4
|
+
parent: NullableElement,
|
|
5
|
+
element: NullableElement
|
|
6
|
+
): number {
|
|
7
|
+
if (!parent || !element) {
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const parentWidth = parent.getBoundingClientRect().width;
|
|
12
|
+
const elementWidth = element.getBoundingClientRect().width;
|
|
13
|
+
return Math.floor(parentWidth / elementWidth);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function elementIndexInRow(
|
|
17
|
+
parent: NullableElement,
|
|
18
|
+
element: NullableElement
|
|
19
|
+
): number {
|
|
20
|
+
if (!parent || !element) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const elementWidth = element.getBoundingClientRect().width;
|
|
25
|
+
const elementLeft = element.getBoundingClientRect().left;
|
|
26
|
+
const parentLeft = parent.getBoundingClientRect().left;
|
|
27
|
+
|
|
28
|
+
return Math.floor((elementLeft - parentLeft) / elementWidth);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function rowNumber(
|
|
32
|
+
parent: NullableElement,
|
|
33
|
+
element: NullableElement
|
|
34
|
+
): number {
|
|
35
|
+
if (!parent || !element) {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const elementHeight = element.getBoundingClientRect().height;
|
|
40
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
41
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
42
|
+
return Math.round((elementTop - parentTop) / elementHeight);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function hasNextRow(
|
|
46
|
+
parent: NullableElement,
|
|
47
|
+
element: NullableElement
|
|
48
|
+
): boolean {
|
|
49
|
+
if (!parent || !element) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const elementHeight = element.getBoundingClientRect().height;
|
|
54
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
55
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
56
|
+
const parentHeight = parent.getBoundingClientRect().height;
|
|
57
|
+
|
|
58
|
+
return Math.round(elementTop - parentTop + elementHeight) < parentHeight;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getRowElements(
|
|
62
|
+
elements: HTMLElement[],
|
|
63
|
+
row: number,
|
|
64
|
+
elementsInRow: number
|
|
65
|
+
): HTMLElement[] {
|
|
66
|
+
if (row === -1) {
|
|
67
|
+
const lastRow = Math.floor((elements.length - 1) / elementsInRow);
|
|
68
|
+
const firstElementIndex = lastRow * elementsInRow;
|
|
69
|
+
const lastElementIndex = elements.length - 1;
|
|
70
|
+
return elements.slice(firstElementIndex, lastElementIndex + 1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return elements.slice(row * elementsInRow, (row + 1) * elementsInRow);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getNextRowElements(
|
|
77
|
+
allElements: HTMLElement[],
|
|
78
|
+
currentRow: number,
|
|
79
|
+
elementsInRow: number
|
|
80
|
+
): HTMLElement[] {
|
|
81
|
+
const nextRow = currentRow + 1;
|
|
82
|
+
|
|
83
|
+
if (nextRow * elementsInRow > allElements.length) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return getRowElements(allElements, nextRow, elementsInRow);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function getElementInRow(
|
|
91
|
+
elements: HTMLElement[],
|
|
92
|
+
row: number,
|
|
93
|
+
elementsInRow: number,
|
|
94
|
+
indexInRow: number
|
|
95
|
+
): NullableElement {
|
|
96
|
+
const rowElements = getRowElements(elements, row, elementsInRow);
|
|
97
|
+
// get element, default to last
|
|
98
|
+
return rowElements[indexInRow] || rowElements[rowElements.length - 1] || null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getElementInNextRow(
|
|
102
|
+
allElements: HTMLElement[],
|
|
103
|
+
currentRow: number,
|
|
104
|
+
elementsInRow: number,
|
|
105
|
+
index: number
|
|
106
|
+
): NullableElement {
|
|
107
|
+
const nextRowElements = getNextRowElements(
|
|
108
|
+
allElements,
|
|
109
|
+
currentRow,
|
|
110
|
+
elementsInRow
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// return item in index, or last item in row
|
|
114
|
+
return (
|
|
115
|
+
nextRowElements[index] ||
|
|
116
|
+
nextRowElements[nextRowElements.length - 1] ||
|
|
117
|
+
null
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function getElementInPrevRow(
|
|
122
|
+
allElements: HTMLElement[],
|
|
123
|
+
currentRow: number,
|
|
124
|
+
elementsInRow: number,
|
|
125
|
+
index: number
|
|
126
|
+
): NullableElement {
|
|
127
|
+
const prevRowElements = getRowElements(
|
|
128
|
+
allElements,
|
|
129
|
+
currentRow - 1,
|
|
130
|
+
elementsInRow
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// default to last
|
|
134
|
+
return (
|
|
135
|
+
prevRowElements[index] ||
|
|
136
|
+
prevRowElements[prevRowElements.length - 1] ||
|
|
137
|
+
null
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function firstVisibleElementInContainer(
|
|
142
|
+
parent: NullableElement,
|
|
143
|
+
elements: HTMLElement[]
|
|
144
|
+
): NullableElement {
|
|
145
|
+
if (!parent || !elements.length) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
150
|
+
const parentBottom = parent.getBoundingClientRect().bottom;
|
|
151
|
+
|
|
152
|
+
const visibleElements = elements.find(element => {
|
|
153
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
154
|
+
const elementBottom = element.getBoundingClientRect().bottom;
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
(elementTop >= parentTop && elementTop <= parentBottom) ||
|
|
158
|
+
(elementBottom >= parentTop && elementBottom <= parentBottom)
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return visibleElements || null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function hasNextElementSibling(element: HTMLElement) {
|
|
166
|
+
return !!element.nextElementSibling;
|
|
167
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NullableElement } from './selectors';
|
|
2
|
+
|
|
3
|
+
export function focusElement(element: NullableElement) {
|
|
4
|
+
if (!element) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
requestAnimationFrame(() => {
|
|
9
|
+
element.focus();
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function focusPrevElementSibling(element: NullableElement) {
|
|
14
|
+
if (!element) return;
|
|
15
|
+
|
|
16
|
+
const prev = element.previousElementSibling as HTMLElement;
|
|
17
|
+
|
|
18
|
+
focusElement(prev);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function focusNextElementSibling(element: NullableElement) {
|
|
22
|
+
if (!element) return;
|
|
23
|
+
|
|
24
|
+
const next = element.nextElementSibling as HTMLElement;
|
|
25
|
+
|
|
26
|
+
focusElement(next);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function focusFirstElementChild(element: NullableElement) {
|
|
30
|
+
if (!element) return;
|
|
31
|
+
|
|
32
|
+
const first = element.firstElementChild as HTMLElement;
|
|
33
|
+
|
|
34
|
+
focusElement(first);
|
|
35
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import {
|
|
2
|
+
elementCountInRow,
|
|
3
|
+
elementIndexInRow,
|
|
4
|
+
getElementInNextRow,
|
|
5
|
+
getElementInPrevRow,
|
|
6
|
+
getElementInRow,
|
|
7
|
+
hasNextRow,
|
|
8
|
+
rowNumber
|
|
9
|
+
} from './elementPositionInRow';
|
|
10
|
+
import { focusElement } from './focusElement';
|
|
11
|
+
import {
|
|
12
|
+
allVisibleEmojis,
|
|
13
|
+
closestCategory,
|
|
14
|
+
firstVisibleEmoji,
|
|
15
|
+
lastVisibleEmoji,
|
|
16
|
+
nextCategory,
|
|
17
|
+
nextVisibleEmoji,
|
|
18
|
+
NullableElement,
|
|
19
|
+
prevCategory,
|
|
20
|
+
prevVisibleEmoji,
|
|
21
|
+
closestCategoryContent
|
|
22
|
+
} from './selectors';
|
|
23
|
+
|
|
24
|
+
export function focusFirstVisibleEmoji(parent: NullableElement) {
|
|
25
|
+
focusElement(firstVisibleEmoji(parent));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function focusAndClickFirstVisibleEmoji(parent: NullableElement) {
|
|
29
|
+
const firstEmoji = firstVisibleEmoji(parent);
|
|
30
|
+
|
|
31
|
+
focusElement(firstEmoji);
|
|
32
|
+
firstEmoji?.click();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function focusLastVisibleEmoji(parent: NullableElement) {
|
|
36
|
+
focusElement(lastVisibleEmoji(parent));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function focusNextVisibleEmoji(element: NullableElement) {
|
|
40
|
+
if (!element) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const next = nextVisibleEmoji(element);
|
|
45
|
+
|
|
46
|
+
if (!next) {
|
|
47
|
+
return focusFirstVisibleEmoji(nextCategory(element));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
focusElement(next);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function focusPrevVisibleEmoji(element: NullableElement) {
|
|
54
|
+
if (!element) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const prev = prevVisibleEmoji(element);
|
|
59
|
+
|
|
60
|
+
if (!prev) {
|
|
61
|
+
return focusLastVisibleEmoji(prevCategory(element));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
focusElement(prev);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function focusVisibleEmojiOneRowUp(
|
|
68
|
+
element: NullableElement,
|
|
69
|
+
exitUp: () => void
|
|
70
|
+
) {
|
|
71
|
+
if (!element) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const prev = visibleEmojiOneRowUp(element);
|
|
76
|
+
|
|
77
|
+
if (!prev) {
|
|
78
|
+
return exitUp();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
focusElement(prev);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function focusVisibleEmojiOneRowDown(element: NullableElement) {
|
|
85
|
+
if (!element) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const next = visibleEmojiOneRowDown(element);
|
|
90
|
+
|
|
91
|
+
return focusElement(next);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function visibleEmojiOneRowUp(element: HTMLElement) {
|
|
95
|
+
if (!element) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const categoryContent = closestCategoryContent(element);
|
|
100
|
+
const category = closestCategory(categoryContent);
|
|
101
|
+
const indexInRow = elementIndexInRow(categoryContent, element);
|
|
102
|
+
const row = rowNumber(categoryContent, element);
|
|
103
|
+
const countInRow = elementCountInRow(categoryContent, element);
|
|
104
|
+
|
|
105
|
+
if (row === 0) {
|
|
106
|
+
const prevVisibleCategory = prevCategory(category);
|
|
107
|
+
|
|
108
|
+
if (!prevVisibleCategory) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return getElementInRow(
|
|
113
|
+
allVisibleEmojis(prevVisibleCategory),
|
|
114
|
+
-1, // last row
|
|
115
|
+
countInRow,
|
|
116
|
+
indexInRow
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return getElementInPrevRow(
|
|
121
|
+
allVisibleEmojis(categoryContent),
|
|
122
|
+
row,
|
|
123
|
+
countInRow,
|
|
124
|
+
indexInRow
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function visibleEmojiOneRowDown(element: HTMLElement) {
|
|
129
|
+
if (!element) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const categoryContent = closestCategoryContent(element);
|
|
134
|
+
const category = closestCategory(categoryContent);
|
|
135
|
+
const indexInRow = elementIndexInRow(categoryContent, element);
|
|
136
|
+
const row = rowNumber(categoryContent, element);
|
|
137
|
+
const countInRow = elementCountInRow(categoryContent, element);
|
|
138
|
+
if (!hasNextRow(categoryContent, element)) {
|
|
139
|
+
const nextVisibleCategory = nextCategory(category);
|
|
140
|
+
|
|
141
|
+
if (!nextVisibleCategory) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return getElementInRow(
|
|
146
|
+
allVisibleEmojis(nextVisibleCategory),
|
|
147
|
+
0,
|
|
148
|
+
countInRow,
|
|
149
|
+
indexInRow
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const itemInNextRow = getElementInNextRow(
|
|
154
|
+
allVisibleEmojis(categoryContent),
|
|
155
|
+
row,
|
|
156
|
+
countInRow,
|
|
157
|
+
indexInRow
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return itemInNextRow;
|
|
161
|
+
}
|
package/src/DomUtils/scrollTo.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useBodyRef } from '../components/context/ElementRefContext';
|
|
4
|
+
|
|
5
|
+
import { NullableElement } from './selectors';
|
|
6
|
+
|
|
7
|
+
export function scrollTo(root: NullableElement, top: number = 0) {
|
|
2
8
|
const $eprBody = root ? root.querySelector('.epr-body') : null;
|
|
3
9
|
|
|
4
10
|
if (!root || !$eprBody) {
|
|
@@ -9,3 +15,18 @@ export function scrollTo(root: HTMLElement | null, top: number = 0) {
|
|
|
9
15
|
$eprBody.scrollTop = top + 1;
|
|
10
16
|
});
|
|
11
17
|
}
|
|
18
|
+
|
|
19
|
+
export function useScrollTo() {
|
|
20
|
+
const BodyRef = useBodyRef();
|
|
21
|
+
|
|
22
|
+
return useCallback(
|
|
23
|
+
(top: number) => {
|
|
24
|
+
requestAnimationFrame(() => {
|
|
25
|
+
if (BodyRef.current) {
|
|
26
|
+
BodyRef.current.scrollTop = top;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
[BodyRef]
|
|
31
|
+
);
|
|
32
|
+
}
|