emoji-picker-react 4.0.0-rc.19 → 4.0.0-rc.21
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 +44 -4
- package/dist/DomUtils/classNames.d.ts +6 -1
- package/dist/DomUtils/elementPositionInRow.d.ts +10 -0
- package/dist/DomUtils/emojiElementRef.d.ts +4 -3
- package/dist/DomUtils/focusElement.d.ts +5 -0
- package/dist/DomUtils/getActiveElement.d.ts +2 -0
- package/dist/DomUtils/keyboardNavigation.d.ts +8 -0
- package/dist/DomUtils/scrollCategoryIntoView.d.ts +2 -1
- package/dist/DomUtils/scrollTo.d.ts +3 -1
- package/dist/DomUtils/selectors.d.ts +23 -11
- package/dist/components/context/ElementRefContext.d.ts +9 -13
- package/dist/components/context/PickerContext.d.ts +1 -1
- package/dist/components/emoji/Emoji.d.ts +2 -2
- package/dist/components/footer/Preview.d.ts +1 -1
- package/dist/config/config.d.ts +12 -15
- package/dist/config/useConfig.d.ts +2 -1
- package/dist/dataUtils/emojiSelectors.d.ts +2 -2
- package/dist/emoji-picker-react.cjs.development.css +7 -7
- package/dist/emoji-picker-react.cjs.development.js +1119 -302
- 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 +1129 -312
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/useCloseAllOpenToggles.d.ts +1 -4
- package/dist/hooks/useDebouncedState.d.ts +1 -1
- 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/useKeyboardNavigation.d.ts +1 -0
- package/dist/hooks/useMouseDownHandlers.d.ts +3 -2
- package/package.json +7 -4
- package/src/DomUtils/classNames.ts +9 -1
- package/src/DomUtils/elementPositionInRow.ts +169 -0
- package/src/DomUtils/emojiElementRef.ts +4 -3
- package/src/DomUtils/focusElement.ts +35 -0
- package/src/DomUtils/getActiveElement.ts +5 -0
- package/src/DomUtils/keyboardNavigation.ts +159 -0
- package/src/DomUtils/scrollCategoryIntoView.ts +2 -1
- package/src/DomUtils/scrollTo.ts +22 -1
- package/src/DomUtils/selectors.ts +157 -32
- package/src/EmojiPickerReact.css +57 -29
- package/src/components/ErrorBoundary.tsx +1 -0
- package/src/components/body/EmojiCategory.css +14 -20
- package/src/components/body/EmojiCategory.tsx +3 -3
- package/src/components/body/EmojiList.tsx +8 -7
- package/src/components/body/EmojiVariationPicker.tsx +3 -3
- package/src/components/body/Suggested.tsx +3 -1
- package/src/components/context/ElementRefContext.tsx +46 -19
- package/src/components/context/PickerContext.tsx +16 -14
- package/src/components/emoji/Emoji.css +7 -2
- package/src/components/emoji/Emoji.tsx +10 -10
- package/src/components/footer/Preview.css +1 -1
- package/src/components/footer/Preview.tsx +13 -16
- package/src/components/header/Search.css +7 -7
- package/src/components/header/Search.tsx +6 -4
- package/src/components/header/SkinTonePicker.css +12 -5
- package/src/components/header/SkinTonePicker.tsx +11 -3
- package/src/components/main/PickerMain.tsx +6 -2
- package/src/components/navigation/CategoryNavigation.css +11 -0
- package/src/components/navigation/CategoryNavigation.tsx +5 -2
- package/src/config/config.ts +39 -10
- package/src/config/useConfig.ts +6 -5
- package/src/dataUtils/emojiSelectors.ts +3 -2
- package/src/dataUtils/suggested.ts +1 -0
- package/src/hooks/preloadEmoji.ts +1 -1
- package/src/hooks/useActiveCategoryScrollDetection.ts +7 -4
- package/src/hooks/useCloseAllOpenToggles.ts +7 -5
- package/src/hooks/useDebouncedState.ts +10 -7
- package/src/hooks/useEmojiPreviewEvents.ts +90 -0
- package/src/hooks/useFilter.ts +41 -21
- package/src/hooks/useFocus.ts +40 -0
- package/src/hooks/useInitialLoad.ts +1 -0
- package/src/hooks/useKeyboardNavigation.ts +389 -0
- package/src/hooks/useMouseDownHandlers.ts +100 -74
- package/src/hooks/useOnScroll.ts +2 -2
- package/src/index.tsx +3 -1
- package/dist/hooks/useEmojiElements.d.ts +0 -1
- package/dist/hooks/useEmojiMouseEnter.d.ts +0 -3
- package/src/hooks/useEmojiElements.ts +0 -7
- package/src/hooks/useEmojiMouseEnter.ts +0 -59
|
@@ -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;
|
|
@@ -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;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-rc.
|
|
2
|
+
"version": "4.0.0-rc.21",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"start": "tsdx watch",
|
|
15
15
|
"build": "node ./scripts/prepare.js && tsdx build",
|
|
16
16
|
"test": "tsdx test --passWithNoTests",
|
|
17
|
-
"lint": "
|
|
17
|
+
"lint": "eslint ./src --ext .ts,.tsx",
|
|
18
18
|
"prepare": "tsdx build",
|
|
19
19
|
"size": "size-limit",
|
|
20
20
|
"analyze": "size-limit --why",
|
|
@@ -58,6 +58,8 @@
|
|
|
58
58
|
"@storybook/react": "^6.5.10",
|
|
59
59
|
"@types/react": "^18.0.17",
|
|
60
60
|
"@types/react-dom": "^18.0.6",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^5.36.2",
|
|
62
|
+
"@typescript-eslint/parser": "^5.36.2",
|
|
61
63
|
"autoprefixer": "^10.4.8",
|
|
62
64
|
"babel-loader": "^8.2.5",
|
|
63
65
|
"cssnano": "^5.1.13",
|
|
@@ -77,12 +79,13 @@
|
|
|
77
79
|
"rollup-plugin-postcss": "^4.0.2",
|
|
78
80
|
"size-limit": "^8.0.1",
|
|
79
81
|
"tiny-invariant": "^1.2.0",
|
|
80
|
-
"tinykeys": "^1.4.0",
|
|
81
82
|
"tsdx": "^0.14.1",
|
|
82
83
|
"tslib": "^2.4.0",
|
|
83
84
|
"typescript": "^4.7.4"
|
|
84
85
|
},
|
|
85
86
|
"dependencies": {
|
|
86
|
-
"clsx": "^1.2.1"
|
|
87
|
+
"clsx": "^1.2.1",
|
|
88
|
+
"eslint-plugin-react": "^7.31.8",
|
|
89
|
+
"eslint-plugin-react-hooks": "^4.6.0"
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -2,5 +2,13 @@ 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
|
+
}
|
|
11
|
+
|
|
12
|
+
export function asSelectors(...classNames: ClassNames[]): string {
|
|
13
|
+
return classNames.map(c => `.${c}`).join('');
|
|
6
14
|
}
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
|
|
14
|
+
return Math.floor(parentWidth / elementWidth);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function elementIndexInRow(
|
|
18
|
+
parent: NullableElement,
|
|
19
|
+
element: NullableElement
|
|
20
|
+
): number {
|
|
21
|
+
if (!parent || !element) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const elementWidth = element.getBoundingClientRect().width;
|
|
26
|
+
const elementLeft = element.getBoundingClientRect().left;
|
|
27
|
+
const parentLeft = parent.getBoundingClientRect().left;
|
|
28
|
+
|
|
29
|
+
return Math.floor((elementLeft - parentLeft) / elementWidth);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function rowNumber(
|
|
33
|
+
parent: NullableElement,
|
|
34
|
+
element: NullableElement
|
|
35
|
+
): number {
|
|
36
|
+
if (!parent || !element) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const elementHeight = element.getBoundingClientRect().height;
|
|
41
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
42
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
43
|
+
|
|
44
|
+
return Math.floor((elementTop - parentTop) / elementHeight) - 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function hasNextRow(
|
|
48
|
+
parent: NullableElement,
|
|
49
|
+
element: NullableElement
|
|
50
|
+
): boolean {
|
|
51
|
+
if (!parent || !element) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const elementHeight = element.getBoundingClientRect().height;
|
|
56
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
57
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
58
|
+
const parentHeight = parent.getBoundingClientRect().height;
|
|
59
|
+
|
|
60
|
+
return elementTop - parentTop + elementHeight < parentHeight;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getRowElements(
|
|
64
|
+
elements: HTMLElement[],
|
|
65
|
+
row: number,
|
|
66
|
+
elementsInRow: number
|
|
67
|
+
): HTMLElement[] {
|
|
68
|
+
if (row === -1) {
|
|
69
|
+
const lastRow = Math.floor(elements.length / elementsInRow);
|
|
70
|
+
const firstElementIndex = lastRow * elementsInRow;
|
|
71
|
+
const lastElementIndex = elements.length - 1;
|
|
72
|
+
return elements.slice(firstElementIndex, lastElementIndex + 1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return elements.slice(row * elementsInRow, (row + 1) * elementsInRow);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getNextRowElements(
|
|
79
|
+
allElements: HTMLElement[],
|
|
80
|
+
currentRow: number,
|
|
81
|
+
elementsInRow: number
|
|
82
|
+
): HTMLElement[] {
|
|
83
|
+
const nextRow = currentRow + 1;
|
|
84
|
+
|
|
85
|
+
if (nextRow * elementsInRow > allElements.length) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return getRowElements(allElements, nextRow, elementsInRow);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getElementInRow(
|
|
93
|
+
elements: HTMLElement[],
|
|
94
|
+
row: number,
|
|
95
|
+
elementsInRow: number,
|
|
96
|
+
indexInRow: number
|
|
97
|
+
): NullableElement {
|
|
98
|
+
const rowElements = getRowElements(elements, row, elementsInRow);
|
|
99
|
+
// get element, default to last
|
|
100
|
+
return rowElements[indexInRow] || rowElements[rowElements.length - 1] || null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getElementInNextRow(
|
|
104
|
+
allElements: HTMLElement[],
|
|
105
|
+
currentRow: number,
|
|
106
|
+
elementsInRow: number,
|
|
107
|
+
index: number
|
|
108
|
+
): NullableElement {
|
|
109
|
+
const nextRowElements = getNextRowElements(
|
|
110
|
+
allElements,
|
|
111
|
+
currentRow,
|
|
112
|
+
elementsInRow
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// return item in index, or last item in row
|
|
116
|
+
return (
|
|
117
|
+
nextRowElements[index] ||
|
|
118
|
+
nextRowElements[nextRowElements.length - 1] ||
|
|
119
|
+
null
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function getElementInPrevRow(
|
|
124
|
+
allElements: HTMLElement[],
|
|
125
|
+
currentRow: number,
|
|
126
|
+
elementsInRow: number,
|
|
127
|
+
index: number
|
|
128
|
+
): NullableElement {
|
|
129
|
+
const prevRowElements = getRowElements(
|
|
130
|
+
allElements,
|
|
131
|
+
currentRow - 1,
|
|
132
|
+
elementsInRow
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// default to last
|
|
136
|
+
return (
|
|
137
|
+
prevRowElements[index] ||
|
|
138
|
+
prevRowElements[prevRowElements.length - 1] ||
|
|
139
|
+
null
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function firstVisibleElementInContainer(
|
|
144
|
+
parent: NullableElement,
|
|
145
|
+
elements: HTMLElement[]
|
|
146
|
+
): NullableElement {
|
|
147
|
+
if (!parent || !elements.length) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const parentTop = parent.getBoundingClientRect().top;
|
|
152
|
+
const parentBottom = parent.getBoundingClientRect().bottom;
|
|
153
|
+
|
|
154
|
+
const visibleElements = elements.find(element => {
|
|
155
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
156
|
+
const elementBottom = element.getBoundingClientRect().bottom;
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
(elementTop >= parentTop && elementTop <= parentBottom) ||
|
|
160
|
+
(elementBottom >= parentTop && elementBottom <= parentBottom)
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return visibleElements || null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function hasNextElementSibling(element: HTMLElement) {
|
|
168
|
+
return !!element.nextElementSibling;
|
|
169
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ClassNames } from './classNames';
|
|
2
|
+
import { NullableElement } from './selectors';
|
|
2
3
|
|
|
3
|
-
export type EmojiRef = { current:
|
|
4
|
+
export type EmojiRef = { current: NullableElement };
|
|
4
5
|
|
|
5
6
|
export const emojiRef: Record<string, EmojiRef> = {};
|
|
6
7
|
|
|
@@ -29,13 +30,13 @@ export function showEmoji(unified: string): void {
|
|
|
29
30
|
showElement(getEmojiRef(unified).current);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
export function hideElement(element:
|
|
33
|
+
export function hideElement(element: NullableElement): void {
|
|
33
34
|
if (!element) return;
|
|
34
35
|
element.classList.add(ClassNames.hidden);
|
|
35
36
|
element.classList.remove(ClassNames.visible);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
export function showElement(element:
|
|
39
|
+
export function showElement(element: NullableElement): void {
|
|
39
40
|
if (!element) return;
|
|
40
41
|
element.classList.remove(ClassNames.hidden);
|
|
41
42
|
element.classList.add(ClassNames.visible);
|
|
@@ -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,159 @@
|
|
|
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
|
+
} from './selectors';
|
|
22
|
+
|
|
23
|
+
export function focusFirstVisibleEmoji(parent: NullableElement) {
|
|
24
|
+
focusElement(firstVisibleEmoji(parent));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function focusAndClickFirstVisibleEmoji(parent: NullableElement) {
|
|
28
|
+
const firstEmoji = firstVisibleEmoji(parent);
|
|
29
|
+
|
|
30
|
+
focusElement(firstEmoji);
|
|
31
|
+
firstEmoji?.click();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function focusLastVisibleEmoji(parent: NullableElement) {
|
|
35
|
+
focusElement(lastVisibleEmoji(parent));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function focusNextVisibleEmoji(element: NullableElement) {
|
|
39
|
+
if (!element) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const next = nextVisibleEmoji(element);
|
|
44
|
+
|
|
45
|
+
if (!next) {
|
|
46
|
+
return focusFirstVisibleEmoji(nextCategory(element));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
focusElement(next);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function focusPrevVisibleEmoji(element: NullableElement) {
|
|
53
|
+
if (!element) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const prev = prevVisibleEmoji(element);
|
|
58
|
+
|
|
59
|
+
if (!prev) {
|
|
60
|
+
return focusLastVisibleEmoji(prevCategory(element));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
focusElement(prev);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function focusVisibleEmojiOneRowUp(
|
|
67
|
+
element: NullableElement,
|
|
68
|
+
exitUp: () => void
|
|
69
|
+
) {
|
|
70
|
+
if (!element) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const prev = visibleEmojiOneRowUp(element);
|
|
75
|
+
|
|
76
|
+
if (!prev) {
|
|
77
|
+
return exitUp();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
focusElement(prev);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function focusVisibleEmojiOneRowDown(element: NullableElement) {
|
|
84
|
+
if (!element) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const next = visibleEmojiOneRowDown(element);
|
|
89
|
+
|
|
90
|
+
return focusElement(next);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function visibleEmojiOneRowUp(element: HTMLElement) {
|
|
94
|
+
if (!element) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const category = closestCategory(element);
|
|
99
|
+
const indexInRow = elementIndexInRow(category, element);
|
|
100
|
+
const row = rowNumber(category, element);
|
|
101
|
+
const countInRow = elementCountInRow(category, element);
|
|
102
|
+
|
|
103
|
+
if (row === 0) {
|
|
104
|
+
const prevVisibleCategory = prevCategory(category);
|
|
105
|
+
|
|
106
|
+
if (!prevVisibleCategory) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return getElementInRow(
|
|
111
|
+
allVisibleEmojis(prevVisibleCategory),
|
|
112
|
+
-1, // last row
|
|
113
|
+
countInRow,
|
|
114
|
+
indexInRow
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return getElementInPrevRow(
|
|
119
|
+
allVisibleEmojis(category),
|
|
120
|
+
row,
|
|
121
|
+
countInRow,
|
|
122
|
+
indexInRow
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function visibleEmojiOneRowDown(element: HTMLElement) {
|
|
127
|
+
if (!element) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const category = closestCategory(element);
|
|
132
|
+
const indexInRow = elementIndexInRow(category, element);
|
|
133
|
+
const row = rowNumber(category, element);
|
|
134
|
+
const countInRow = elementCountInRow(category, element);
|
|
135
|
+
|
|
136
|
+
if (!hasNextRow(category, element)) {
|
|
137
|
+
const nextVisibleCategory = nextCategory(category);
|
|
138
|
+
|
|
139
|
+
if (!nextVisibleCategory) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return getElementInRow(
|
|
144
|
+
allVisibleEmojis(nextVisibleCategory),
|
|
145
|
+
0,
|
|
146
|
+
countInRow,
|
|
147
|
+
indexInRow
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const itemInNextRow = getElementInNextRow(
|
|
152
|
+
allVisibleEmojis(category),
|
|
153
|
+
row,
|
|
154
|
+
countInRow,
|
|
155
|
+
indexInRow
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return itemInNextRow;
|
|
159
|
+
}
|
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
|
+
}
|