@atlaskit/emoji 69.0.1 → 69.0.3
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/CHANGELOG.md +17 -0
- package/afm-cc/tsconfig.json +3 -0
- package/afm-jira/tsconfig.json +3 -0
- package/afm-post-office/tsconfig.json +3 -0
- package/dist/cjs/components/compiled/common/EmojiActions.js +1 -1
- package/dist/cjs/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
- package/dist/cjs/components/compiled/common/EmojiPreviewComponent.js +1 -1
- package/dist/cjs/components/compiled/picker/CategorySelector.compiled.css +24 -0
- package/dist/cjs/components/compiled/picker/CategorySelector.js +161 -0
- package/dist/cjs/components/compiled/picker/EmojiPicker.compiled.css +12 -0
- package/dist/cjs/components/compiled/picker/EmojiPicker.js +109 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerCategoryHeading.js +43 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerComponent.compiled.css +20 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerComponent.js +574 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerEmojiRow.js +76 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerFooter.js +33 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerListSearch.js +93 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerTabPanel.js +60 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
- package/dist/cjs/components/compiled/picker/EmojiPickerVirtualItems.js +86 -0
- package/dist/cjs/components/compiled/picker/VirtualList.compiled.css +10 -0
- package/dist/cjs/components/compiled/picker/VirtualList.js +303 -0
- package/dist/cjs/components/picker/EmojiPickerFooter.js +0 -2
- package/dist/cjs/components/picker/EmojiPickerList.js +219 -145
- package/dist/cjs/components/picker/EmojiPickerTabPanel.js +67 -0
- package/dist/cjs/components/picker/styles.js +1 -10
- package/dist/cjs/index.js +4 -6
- package/dist/cjs/picker.js +5 -7
- package/dist/cjs/util/analytics/analytics.js +1 -1
- package/dist/es2019/components/compiled/common/EmojiActions.js +1 -1
- package/dist/es2019/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
- package/dist/es2019/components/compiled/common/EmojiPreviewComponent.js +1 -1
- package/dist/es2019/components/compiled/picker/CategorySelector.compiled.css +24 -0
- package/dist/es2019/components/compiled/picker/CategorySelector.js +136 -0
- package/dist/es2019/components/compiled/picker/EmojiPicker.compiled.css +12 -0
- package/dist/es2019/components/compiled/picker/EmojiPicker.js +67 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerCategoryHeading.js +30 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerComponent.compiled.css +19 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerComponent.js +506 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerEmojiRow.js +69 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerFooter.js +19 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerListSearch.js +79 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerTabPanel.js +39 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
- package/dist/es2019/components/compiled/picker/EmojiPickerVirtualItems.js +51 -0
- package/dist/es2019/components/compiled/picker/VirtualList.compiled.css +10 -0
- package/dist/es2019/components/compiled/picker/VirtualList.js +288 -0
- package/dist/es2019/components/picker/EmojiPickerFooter.js +1 -1
- package/dist/es2019/components/picker/EmojiPickerList.js +186 -114
- package/dist/es2019/components/picker/EmojiPickerTabPanel.js +48 -0
- package/dist/es2019/components/picker/styles.js +0 -9
- package/dist/es2019/index.js +2 -1
- package/dist/es2019/picker.js +5 -1
- package/dist/es2019/util/analytics/analytics.js +1 -1
- package/dist/esm/components/compiled/common/EmojiActions.js +1 -1
- package/dist/esm/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
- package/dist/esm/components/compiled/common/EmojiPreviewComponent.js +1 -1
- package/dist/esm/components/compiled/picker/CategorySelector.compiled.css +24 -0
- package/dist/esm/components/compiled/picker/CategorySelector.js +151 -0
- package/dist/esm/components/compiled/picker/EmojiPicker.compiled.css +12 -0
- package/dist/esm/components/compiled/picker/EmojiPicker.js +97 -0
- package/dist/esm/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
- package/dist/esm/components/compiled/picker/EmojiPickerCategoryHeading.js +34 -0
- package/dist/esm/components/compiled/picker/EmojiPickerComponent.compiled.css +20 -0
- package/dist/esm/components/compiled/picker/EmojiPickerComponent.js +564 -0
- package/dist/esm/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
- package/dist/esm/components/compiled/picker/EmojiPickerEmojiRow.js +66 -0
- package/dist/esm/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
- package/dist/esm/components/compiled/picker/EmojiPickerFooter.js +24 -0
- package/dist/esm/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
- package/dist/esm/components/compiled/picker/EmojiPickerListSearch.js +83 -0
- package/dist/esm/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
- package/dist/esm/components/compiled/picker/EmojiPickerTabPanel.js +50 -0
- package/dist/esm/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
- package/dist/esm/components/compiled/picker/EmojiPickerVirtualItems.js +76 -0
- package/dist/esm/components/compiled/picker/VirtualList.compiled.css +10 -0
- package/dist/esm/components/compiled/picker/VirtualList.js +293 -0
- package/dist/esm/components/picker/EmojiPickerFooter.js +1 -1
- package/dist/esm/components/picker/EmojiPickerList.js +219 -147
- package/dist/esm/components/picker/EmojiPickerTabPanel.js +59 -0
- package/dist/esm/components/picker/styles.js +0 -9
- package/dist/esm/index.js +2 -1
- package/dist/esm/picker.js +5 -1
- package/dist/esm/util/analytics/analytics.js +1 -1
- package/dist/types/components/compiled/picker/CategorySelector.d.ts +17 -0
- package/dist/types/components/compiled/picker/EmojiPicker.d.ts +44 -0
- package/dist/types/components/compiled/picker/EmojiPickerCategoryHeading.d.ts +13 -0
- package/dist/types/components/compiled/picker/EmojiPickerComponent.d.ts +24 -0
- package/dist/types/components/compiled/picker/EmojiPickerEmojiRow.d.ts +17 -0
- package/dist/types/components/compiled/picker/EmojiPickerFooter.d.ts +8 -0
- package/dist/types/components/compiled/picker/EmojiPickerListSearch.d.ts +11 -0
- package/dist/types/components/compiled/picker/EmojiPickerTabPanel.d.ts +21 -0
- package/dist/types/components/compiled/picker/EmojiPickerVirtualItems.d.ts +35 -0
- package/dist/types/components/compiled/picker/VirtualList.d.ts +42 -0
- package/dist/types/components/picker/EmojiPickerList.d.ts +1 -6
- package/dist/types/components/picker/EmojiPickerTabPanel.d.ts +21 -0
- package/dist/types/components/picker/styles.d.ts +0 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/picker.d.ts +3 -1
- package/dist/types-ts4.5/components/compiled/picker/CategorySelector.d.ts +17 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPicker.d.ts +44 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerCategoryHeading.d.ts +13 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerComponent.d.ts +24 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerEmojiRow.d.ts +17 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerFooter.d.ts +8 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerListSearch.d.ts +11 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerTabPanel.d.ts +21 -0
- package/dist/types-ts4.5/components/compiled/picker/EmojiPickerVirtualItems.d.ts +35 -0
- package/dist/types-ts4.5/components/compiled/picker/VirtualList.d.ts +42 -0
- package/dist/types-ts4.5/components/picker/EmojiPickerList.d.ts +1 -6
- package/dist/types-ts4.5/components/picker/EmojiPickerTabPanel.d.ts +21 -0
- package/dist/types-ts4.5/components/picker/styles.d.ts +0 -1
- package/dist/types-ts4.5/index.d.ts +2 -1
- package/dist/types-ts4.5/picker.d.ts +3 -1
- package/package.json +4 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* EmojiPickerListSearch.tsx generated by @compiled/babel-plugin v0.36.1 */
|
|
2
|
+
import "./EmojiPickerListSearch.compiled.css";
|
|
3
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
+
import SearchIcon from '@atlaskit/icon/core/migration/search';
|
|
5
|
+
import TextField from '@atlaskit/textfield';
|
|
6
|
+
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
7
|
+
import React, { useLayoutEffect, useRef, useState } from 'react';
|
|
8
|
+
import { useIntl } from 'react-intl-next';
|
|
9
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
10
|
+
import { EMOJI_SEARCH_DEBOUNCE } from '../../../util/constants';
|
|
11
|
+
import { messages } from '../../i18n';
|
|
12
|
+
const input = null;
|
|
13
|
+
const pickerSearch = null;
|
|
14
|
+
const searchIcon = null;
|
|
15
|
+
const hidden = null;
|
|
16
|
+
export const emojiPickerSearchTestId = 'emoji-picker-search';
|
|
17
|
+
export const EmojiPickerListSearch = props => {
|
|
18
|
+
const {
|
|
19
|
+
style,
|
|
20
|
+
query,
|
|
21
|
+
isVisible = true,
|
|
22
|
+
resultsCount,
|
|
23
|
+
onChange
|
|
24
|
+
} = props;
|
|
25
|
+
const textRef = useRef(null);
|
|
26
|
+
const [dirty, setDirty] = useState(false);
|
|
27
|
+
const {
|
|
28
|
+
formatMessage
|
|
29
|
+
} = useIntl();
|
|
30
|
+
|
|
31
|
+
// Debounce callback
|
|
32
|
+
const [debouncedSearch] = useDebouncedCallback(value => {
|
|
33
|
+
onChange(value);
|
|
34
|
+
setDirty(true);
|
|
35
|
+
},
|
|
36
|
+
// delay in ms
|
|
37
|
+
EMOJI_SEARCH_DEBOUNCE);
|
|
38
|
+
const handleOnChange = e => {
|
|
39
|
+
debouncedSearch(e.target.value);
|
|
40
|
+
};
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
requestAnimationFrame(() => {
|
|
43
|
+
if (textRef) {
|
|
44
|
+
var _textRef$current;
|
|
45
|
+
(_textRef$current = textRef.current) === null || _textRef$current === void 0 ? void 0 : _textRef$current.focus();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}, []);
|
|
49
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
50
|
+
style: style,
|
|
51
|
+
className: ax(["_vchhusvi _ca0qutpp _n3tdutpp _19bvutpp _u5f3utpp _1bsb1osq", !isVisible && "_tzy4idpf _3um015vq _1e0cglyw"])
|
|
52
|
+
}, /*#__PURE__*/React.createElement(VisuallyHidden, {
|
|
53
|
+
id: "emoji-search-results-status",
|
|
54
|
+
role: "status"
|
|
55
|
+
}, dirty && query === '' && formatMessage(messages.searchResultsStatusSeeAll), query !== '' && formatMessage(messages.searchResultsStatusSeeAll, {
|
|
56
|
+
// change to messages.searchResultsStatus once translated
|
|
57
|
+
count: resultsCount
|
|
58
|
+
})), /*#__PURE__*/React.createElement(TextField, {
|
|
59
|
+
role: "searchbox",
|
|
60
|
+
"aria-label": formatMessage(messages.searchLabel),
|
|
61
|
+
autoComplete: "off",
|
|
62
|
+
name: "search",
|
|
63
|
+
placeholder: `${formatMessage(messages.searchPlaceholder)}...`,
|
|
64
|
+
defaultValue: query || '',
|
|
65
|
+
onChange: handleOnChange,
|
|
66
|
+
elemBeforeInput: /*#__PURE__*/React.createElement("span", {
|
|
67
|
+
className: ax(["_tzy4105o _18u01i6y"])
|
|
68
|
+
}, /*#__PURE__*/React.createElement(SearchIcon, {
|
|
69
|
+
LEGACY_margin: "0 0 0 2px",
|
|
70
|
+
color: "currentColor",
|
|
71
|
+
spacing: "spacious",
|
|
72
|
+
label: ""
|
|
73
|
+
})),
|
|
74
|
+
testId: emojiPickerSearchTestId,
|
|
75
|
+
ref: textRef,
|
|
76
|
+
isCompact: true,
|
|
77
|
+
className: ax(["_11c82smr _12ji1r31 _1qu2glyw _12y31o36 _vchhusvi _syaz1kw7 _80om1kw7 _1q51t94y _y4tize3t _85i5v77o _bozg12x7 _1bsb1osq _13xeglyw _1goxglyw"])
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* EmojiPickerTabPanel.tsx generated by @compiled/babel-plugin v0.36.1 */
|
|
2
|
+
import "./EmojiPickerTabPanel.compiled.css";
|
|
3
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
+
import React, { PureComponent } from 'react';
|
|
5
|
+
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
6
|
+
import { injectIntl } from 'react-intl-next';
|
|
7
|
+
import { messages } from '../../i18n';
|
|
8
|
+
import { RENDER_EMOJI_PICKER_LIST_TESTID } from '../../picker/EmojiPickerList';
|
|
9
|
+
const emojiPickerList = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* TODO: have to use class component here as unit test is relying on ref.root. Will refactor this whole file + EmojiPickerList to functional component in future
|
|
13
|
+
* ticket: COLLAB-2317
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
class EmojiPickerTabPanelInternal extends PureComponent {
|
|
17
|
+
render() {
|
|
18
|
+
const {
|
|
19
|
+
intl: {
|
|
20
|
+
formatMessage
|
|
21
|
+
},
|
|
22
|
+
children,
|
|
23
|
+
showSearchResults
|
|
24
|
+
} = this.props;
|
|
25
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
26
|
+
ref: "root",
|
|
27
|
+
"data-testid": RENDER_EMOJI_PICKER_LIST_TESTID,
|
|
28
|
+
id: RENDER_EMOJI_PICKER_LIST_TESTID,
|
|
29
|
+
role: "tabpanel",
|
|
30
|
+
"aria-label": formatMessage(messages.emojiPickerListPanel),
|
|
31
|
+
className: ax(["_16jlkb7n _1o9zkb7n _i0dl1wug _1e0c1txw _2lx21bp4 _4t3iidpf"])
|
|
32
|
+
}, /*#__PURE__*/React.createElement(VisuallyHidden, {
|
|
33
|
+
id: "emoji-picker-table-description"
|
|
34
|
+
}, formatMessage(messages.emojiPickerGrid, {
|
|
35
|
+
showSearchResults
|
|
36
|
+
})), children);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export default injectIntl(EmojiPickerTabPanelInternal);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* EmojiPickerVirtualItems.tsx generated by @compiled/babel-plugin v0.36.1 */
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
import "./EmojiPickerVirtualItems.compiled.css";
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
7
|
+
import Spinner from '@atlaskit/spinner';
|
|
8
|
+
import EmojiPickerCategoryHeading from './EmojiPickerCategoryHeading';
|
|
9
|
+
import EmojiPickerEmojiRow from './EmojiPickerEmojiRow';
|
|
10
|
+
import { sizes } from '../../picker/EmojiPickerSizes';
|
|
11
|
+
const emojiPickerSpinner = null;
|
|
12
|
+
export class AbstractItem {
|
|
13
|
+
constructor(props, height) {
|
|
14
|
+
this.props = props;
|
|
15
|
+
this.height = height;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class EmojisRowItem extends AbstractItem {
|
|
19
|
+
constructor(props) {
|
|
20
|
+
super(props, sizes.emojiRowHeight);
|
|
21
|
+
_defineProperty(this, "renderItem", context => /*#__PURE__*/React.createElement(EmojiPickerEmojiRow, _extends({}, this.props, {
|
|
22
|
+
virtualItemContext: context
|
|
23
|
+
})));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export class LoadingItem extends AbstractItem {
|
|
27
|
+
constructor() {
|
|
28
|
+
super({}, sizes.loadingRowHeight);
|
|
29
|
+
_defineProperty(this, "renderItem", () => /*#__PURE__*/React.createElement("div", {
|
|
30
|
+
className: ax(["_1e0c1txw _1bsb1osq _4t3i1w81 _1bah1h6o _4cvr1h6o _nphsidpf _t1edidpf _1t3b1wug"])
|
|
31
|
+
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Spinner, {
|
|
32
|
+
size: "medium"
|
|
33
|
+
}))));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class CategoryHeadingItem extends AbstractItem {
|
|
37
|
+
constructor(props) {
|
|
38
|
+
super(props, sizes.categoryHeadingHeight);
|
|
39
|
+
_defineProperty(this, "renderItem", () => /*#__PURE__*/React.createElement(EmojiPickerCategoryHeading, this.props));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export const virtualItemRenderer = (rows, context) => {
|
|
43
|
+
const {
|
|
44
|
+
index,
|
|
45
|
+
key
|
|
46
|
+
} = context;
|
|
47
|
+
const row = rows[index];
|
|
48
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
49
|
+
key: key
|
|
50
|
+
}, row && row.renderItem(context));
|
|
51
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
._154iidpf{top:0}
|
|
2
|
+
._18m91wug{overflow-y:auto}
|
|
3
|
+
._1bsb1osq{width:100%}
|
|
4
|
+
._1ltvidpf{left:0}
|
|
5
|
+
._1reo15vq{overflow-x:hidden}
|
|
6
|
+
._kqswstnw{position:absolute}
|
|
7
|
+
._n3tdu2gc{padding-bottom:var(--ds-space-100,8px)}
|
|
8
|
+
._1hvw1o36:focus{outline-width:medium}
|
|
9
|
+
._49pcglyw:focus{outline-style:none}
|
|
10
|
+
._nt751r31:focus{outline-color:currentColor}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/* VirtualList.tsx generated by @compiled/babel-plugin v0.36.1 */
|
|
2
|
+
import "./VirtualList.compiled.css";
|
|
3
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
+
import React, { useCallback, useImperativeHandle } from 'react';
|
|
5
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
6
|
+
import { useEmojiPickerListContext } from '../../../hooks/useEmojiPickerListContext';
|
|
7
|
+
import { EMOJIPICKERLIST_KEYBOARD_KEYS_SUPPORTED, EMOJI_LIST_COLUMNS, EMOJI_LIST_PAGE_COUNT, KeyboardNavigationDirection, KeyboardKeys } from '../../../util/constants';
|
|
8
|
+
const virtualList = null;
|
|
9
|
+
const virtualRowStyle = null;
|
|
10
|
+
export const virtualListScrollContainerTestId = 'virtual-list-scroll-container';
|
|
11
|
+
export const VirtualList = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
12
|
+
const parentRef = React.useRef(null);
|
|
13
|
+
const virtualistItemsRef = React.useRef(null);
|
|
14
|
+
const {
|
|
15
|
+
rowRenderer,
|
|
16
|
+
onRowsRendered,
|
|
17
|
+
scrollToAlignment,
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
rowCount
|
|
21
|
+
} = props;
|
|
22
|
+
const {
|
|
23
|
+
currentEmojisFocus,
|
|
24
|
+
setEmojisFocus
|
|
25
|
+
} = useEmojiPickerListContext();
|
|
26
|
+
const getVirtualizerOptions = () => {
|
|
27
|
+
const {
|
|
28
|
+
rowCount,
|
|
29
|
+
rowHeight,
|
|
30
|
+
overscanRowCount
|
|
31
|
+
} = props;
|
|
32
|
+
return {
|
|
33
|
+
count: rowCount,
|
|
34
|
+
getScrollElement: () => parentRef.current,
|
|
35
|
+
estimateSize: rowHeight,
|
|
36
|
+
overscan: overscanRowCount,
|
|
37
|
+
onChange: () => {
|
|
38
|
+
const startIndex = getFirstVisibleListElementIndex();
|
|
39
|
+
onRowsRendered({
|
|
40
|
+
startIndex
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
scrollPaddingStart: 28,
|
|
44
|
+
scrollPaddingEnd: 28
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const rowVirtualizer = useVirtualizer(getVirtualizerOptions());
|
|
48
|
+
const isElementVisible = element => {
|
|
49
|
+
const parent = parentRef.current;
|
|
50
|
+
const elementRect = element.getBoundingClientRect();
|
|
51
|
+
const parentRect = parent.getBoundingClientRect();
|
|
52
|
+
const elemTop = elementRect.top;
|
|
53
|
+
const elemBottom = elementRect.bottom;
|
|
54
|
+
const parentTop = parentRect.top;
|
|
55
|
+
const parentBottom = parentRect.bottom;
|
|
56
|
+
|
|
57
|
+
// Only completely visible elements return true:
|
|
58
|
+
const isVisible = elemTop >= parentTop && elemBottom <= parentBottom;
|
|
59
|
+
return isVisible;
|
|
60
|
+
};
|
|
61
|
+
const getFirstVisibleListElementIndex = useCallback(() => {
|
|
62
|
+
var _parentRef$current, _parentRef$current$fi;
|
|
63
|
+
const virtualList = rowVirtualizer.getVirtualItems();
|
|
64
|
+
const renderedElements = (_parentRef$current = parentRef.current) === null || _parentRef$current === void 0 ? void 0 : (_parentRef$current$fi = _parentRef$current.firstChild) === null || _parentRef$current$fi === void 0 ? void 0 : _parentRef$current$fi.childNodes;
|
|
65
|
+
if (virtualList.length === 0 || !renderedElements || renderedElements.length === 0) {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
// Convert NodeListOf<ChildNodes> to ChildNodes[]
|
|
69
|
+
const renderedElementsToArray = Array.from(renderedElements);
|
|
70
|
+
const firstVisibleIndex = renderedElementsToArray.findIndex(elem => isElementVisible(elem));
|
|
71
|
+
if (firstVisibleIndex !== -1) {
|
|
72
|
+
var _virtualList$firstVis;
|
|
73
|
+
return ((_virtualList$firstVis = virtualList[firstVisibleIndex]) === null || _virtualList$firstVis === void 0 ? void 0 : _virtualList$firstVis.index) || 0;
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}, [rowVirtualizer]);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Recurisive function to find next available emoji and it's focus indexes in the grid
|
|
80
|
+
*
|
|
81
|
+
* current focus element is at rowIndex.columnIndex
|
|
82
|
+
* if found element then return the element and focus indexes
|
|
83
|
+
* otherwise change row/column till find the element
|
|
84
|
+
* if can't find the element till reach the edge of grid, we keep current focus states
|
|
85
|
+
*
|
|
86
|
+
* @param rowIndex search from row index (0 based)
|
|
87
|
+
* @param columnIndex search from column index (0 based)
|
|
88
|
+
* @param direction search direction
|
|
89
|
+
*/
|
|
90
|
+
const findNextEmoji = useCallback((rowIndex, columnIndex, direction) => {
|
|
91
|
+
var _virtualistItemsRef$c;
|
|
92
|
+
const emojiToFocus = (_virtualistItemsRef$c = virtualistItemsRef.current) === null || _virtualistItemsRef$c === void 0 ? void 0 : _virtualistItemsRef$c.querySelector(`[data-focus-index="${rowIndex}-${columnIndex}"]`);
|
|
93
|
+
const lastRowIndex = rowCount - 1;
|
|
94
|
+
const lastColumnIndex = EMOJI_LIST_COLUMNS - 1;
|
|
95
|
+
if (emojiToFocus) {
|
|
96
|
+
return {
|
|
97
|
+
element: emojiToFocus,
|
|
98
|
+
rowIndex,
|
|
99
|
+
columnIndex
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
switch (direction) {
|
|
103
|
+
case KeyboardNavigationDirection.Down:
|
|
104
|
+
if (rowIndex >= lastRowIndex) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
// find emoji in same column but lower row
|
|
108
|
+
return findNextEmoji(rowIndex + 1, columnIndex, KeyboardNavigationDirection.Down);
|
|
109
|
+
case KeyboardNavigationDirection.Up:
|
|
110
|
+
if (rowIndex <= 0) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
// find emoji in same column but upper row
|
|
114
|
+
return findNextEmoji(rowIndex - 1, columnIndex, KeyboardNavigationDirection.Up);
|
|
115
|
+
case KeyboardNavigationDirection.Left:
|
|
116
|
+
if (rowIndex <= 0) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (columnIndex < 0) {
|
|
120
|
+
// find emoji in upper row
|
|
121
|
+
return findNextEmoji(rowIndex - 1, lastColumnIndex, KeyboardNavigationDirection.Left);
|
|
122
|
+
}
|
|
123
|
+
// find emoji on left in the current row
|
|
124
|
+
return findNextEmoji(rowIndex, columnIndex - 1, KeyboardNavigationDirection.Left);
|
|
125
|
+
case KeyboardNavigationDirection.Right:
|
|
126
|
+
if (rowIndex >= lastRowIndex) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
// if no emoji on right, we try first emoji in next row
|
|
130
|
+
return findNextEmoji(rowIndex + 1, 0, KeyboardNavigationDirection.Right);
|
|
131
|
+
default:
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}, [rowCount]);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Find the valid emoji to scroll and focus
|
|
138
|
+
*/
|
|
139
|
+
const scrollToRowAndFocusEmoji = useCallback(emojiToFocus => {
|
|
140
|
+
if (emojiToFocus) {
|
|
141
|
+
var _emojiToFocus$element;
|
|
142
|
+
rowVirtualizer.scrollToIndex(emojiToFocus.rowIndex);
|
|
143
|
+
(_emojiToFocus$element = emojiToFocus.element) === null || _emojiToFocus$element === void 0 ? void 0 : _emojiToFocus$element.focus({
|
|
144
|
+
preventScroll: true
|
|
145
|
+
});
|
|
146
|
+
setEmojisFocus({
|
|
147
|
+
rowIndex: emojiToFocus.rowIndex,
|
|
148
|
+
columnIndex: emojiToFocus.columnIndex
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}, [rowVirtualizer, setEmojisFocus]);
|
|
152
|
+
const focusEmoji = useCallback((rIndex, cIndex, direction, waitForScrollFinish = false) => {
|
|
153
|
+
if (waitForScrollFinish) {
|
|
154
|
+
// scroll to target rowIndex first to ensure the row is rendered in list.
|
|
155
|
+
// used in page up/down, ctrl+Home, ctrl+End
|
|
156
|
+
rowVirtualizer.scrollToIndex(rIndex);
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
const emojiToFocus = findNextEmoji(rIndex, cIndex, direction);
|
|
159
|
+
scrollToRowAndFocusEmoji(emojiToFocus);
|
|
160
|
+
}, 100); // 100ms is virtual list scrolling time
|
|
161
|
+
} else {
|
|
162
|
+
const emojiToFocus = findNextEmoji(rIndex, cIndex, direction);
|
|
163
|
+
scrollToRowAndFocusEmoji(emojiToFocus);
|
|
164
|
+
}
|
|
165
|
+
}, [scrollToRowAndFocusEmoji, findNextEmoji, rowVirtualizer]);
|
|
166
|
+
|
|
167
|
+
// following the guide from https://www.w3.org/WAI/ARIA/apg/patterns/grid/
|
|
168
|
+
const handleKeyDown = e => {
|
|
169
|
+
if (!EMOJIPICKERLIST_KEYBOARD_KEYS_SUPPORTED.includes(e.key)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
e.stopPropagation();
|
|
174
|
+
const lastRowIndex = rowCount - 1;
|
|
175
|
+
const lastColumnIndex = EMOJI_LIST_COLUMNS - 1;
|
|
176
|
+
|
|
177
|
+
// focus first emoji on first row
|
|
178
|
+
if (e.key === KeyboardKeys.Home && e.ctrlKey) {
|
|
179
|
+
focusEmoji(1, 0, KeyboardNavigationDirection.Up, true);
|
|
180
|
+
return;
|
|
181
|
+
} else if (e.key === KeyboardKeys.End && e.ctrlKey) {
|
|
182
|
+
// focus last available emoji on last row
|
|
183
|
+
focusEmoji(lastRowIndex, lastColumnIndex, KeyboardNavigationDirection.Left, true);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
switch (e.key) {
|
|
187
|
+
// navigate to the right column
|
|
188
|
+
case KeyboardKeys.ArrowRight:
|
|
189
|
+
focusEmoji(currentEmojisFocus.rowIndex, currentEmojisFocus.columnIndex + 1, KeyboardNavigationDirection.Right);
|
|
190
|
+
break;
|
|
191
|
+
// navigate to the left column
|
|
192
|
+
case KeyboardKeys.ArrowLeft:
|
|
193
|
+
focusEmoji(currentEmojisFocus.rowIndex, currentEmojisFocus.columnIndex - 1, KeyboardNavigationDirection.Left);
|
|
194
|
+
break;
|
|
195
|
+
// navigate to the down row
|
|
196
|
+
case KeyboardKeys.ArrowDown:
|
|
197
|
+
focusEmoji(currentEmojisFocus.rowIndex === lastRowIndex ? lastRowIndex : currentEmojisFocus.rowIndex + 1, currentEmojisFocus.columnIndex, KeyboardNavigationDirection.Down);
|
|
198
|
+
break;
|
|
199
|
+
// navigate to the row after {EMOJI_LIST_PAGE_COUNT} rows
|
|
200
|
+
case KeyboardKeys.PageDown:
|
|
201
|
+
focusEmoji(currentEmojisFocus.rowIndex + EMOJI_LIST_PAGE_COUNT, currentEmojisFocus.columnIndex, KeyboardNavigationDirection.Down, true);
|
|
202
|
+
break;
|
|
203
|
+
// navigate to the up row
|
|
204
|
+
case KeyboardKeys.ArrowUp:
|
|
205
|
+
focusEmoji(currentEmojisFocus.rowIndex <= 1 ? 1 : currentEmojisFocus.rowIndex - 1, currentEmojisFocus.columnIndex, KeyboardNavigationDirection.Up);
|
|
206
|
+
break;
|
|
207
|
+
// navigate to the row before {EMOJI_LIST_PAGE_COUNT} rows
|
|
208
|
+
case KeyboardKeys.PageUp:
|
|
209
|
+
focusEmoji(currentEmojisFocus.rowIndex - EMOJI_LIST_PAGE_COUNT, currentEmojisFocus.columnIndex, KeyboardNavigationDirection.Up, true);
|
|
210
|
+
break;
|
|
211
|
+
// navigate to the first cell of current row
|
|
212
|
+
case KeyboardKeys.Home:
|
|
213
|
+
focusEmoji(currentEmojisFocus.rowIndex, 0, KeyboardNavigationDirection.Left);
|
|
214
|
+
break;
|
|
215
|
+
// navigate to the last cell of current row
|
|
216
|
+
case KeyboardKeys.End:
|
|
217
|
+
focusEmoji(currentEmojisFocus.rowIndex, lastColumnIndex, KeyboardNavigationDirection.Left);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Exposing a custom ref handle to the parent component EmojiPickerList to trigger scrollToRow via the listRef
|
|
223
|
+
// https://beta.reactjs.org/reference/react/useImperativeHandle
|
|
224
|
+
useImperativeHandle(ref, () => {
|
|
225
|
+
return {
|
|
226
|
+
scrollToRow(index) {
|
|
227
|
+
if (index !== undefined) {
|
|
228
|
+
rowVirtualizer.setOptions({
|
|
229
|
+
...rowVirtualizer.options,
|
|
230
|
+
scrollPaddingStart: 0
|
|
231
|
+
});
|
|
232
|
+
rowVirtualizer.scrollToIndex(index, {
|
|
233
|
+
align: scrollToAlignment
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
scrollToRowAndFocusLastEmoji(index) {
|
|
238
|
+
if (index !== undefined) {
|
|
239
|
+
focusEmoji(index, EMOJI_LIST_COLUMNS, KeyboardNavigationDirection.Left, true);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
scrollToEmojiAndFocus(rowIndex, columnIndex) {
|
|
243
|
+
focusEmoji(rowIndex, columnIndex, KeyboardNavigationDirection.Left, true);
|
|
244
|
+
},
|
|
245
|
+
updateFocusIndex(rowIndex, columnIndex = 0) {
|
|
246
|
+
var _virtualistItemsRef$c2;
|
|
247
|
+
// row could be removed from virtual list after scrolling, we'll update emoji cell tabIndex after losing focus
|
|
248
|
+
if (!((_virtualistItemsRef$c2 = virtualistItemsRef.current) !== null && _virtualistItemsRef$c2 !== void 0 && _virtualistItemsRef$c2.contains(document.activeElement))) {
|
|
249
|
+
setEmojisFocus({
|
|
250
|
+
rowIndex,
|
|
251
|
+
columnIndex
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}, [setEmojisFocus, focusEmoji, rowVirtualizer, scrollToAlignment]);
|
|
257
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
258
|
+
ref: parentRef,
|
|
259
|
+
style: {
|
|
260
|
+
height: `${height}px`,
|
|
261
|
+
width: `${width}px`
|
|
262
|
+
},
|
|
263
|
+
"data-testid": virtualListScrollContainerTestId,
|
|
264
|
+
"aria-labelledby": "emoji-picker-table-description",
|
|
265
|
+
role: "grid",
|
|
266
|
+
className: ax(["_1reo15vq _18m91wug _n3tdu2gc _nt751r31 _49pcglyw _1hvw1o36"])
|
|
267
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
268
|
+
style: {
|
|
269
|
+
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
270
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
271
|
+
width: '100%',
|
|
272
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
|
|
273
|
+
position: 'relative'
|
|
274
|
+
},
|
|
275
|
+
ref: virtualistItemsRef,
|
|
276
|
+
onKeyDown: handleKeyDown,
|
|
277
|
+
role: "presentation"
|
|
278
|
+
}, rowVirtualizer.getVirtualItems().map((virtualRow, index) => /*#__PURE__*/React.createElement("div", {
|
|
279
|
+
key: virtualRow.key,
|
|
280
|
+
style: {
|
|
281
|
+
height: `${virtualRow.size}px`,
|
|
282
|
+
transform: `translateY(${virtualRow.start}px)`
|
|
283
|
+
},
|
|
284
|
+
role: "row",
|
|
285
|
+
"aria-rowindex": index + 1,
|
|
286
|
+
className: ax(["_kqswstnw _154iidpf _1ltvidpf _1bsb1osq"])
|
|
287
|
+
}, rowRenderer(virtualRow)))));
|
|
288
|
+
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { memo } from 'react';
|
|
6
6
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
7
7
|
import { jsx } from '@emotion/react';
|
|
8
|
-
import { EmojiPreviewComponent } from '../common/EmojiPreviewComponent';
|
|
8
|
+
import { EmojiPreviewComponent } from '../common/EmojiPreviewComponent';
|
|
9
9
|
import { emojiPickerFooter, emojiPickerFooterWithTopShadow } from './styles';
|
|
10
10
|
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
|
|
11
11
|
const previewFooterClassnames = [emojiPickerFooter, emojiPickerFooterWithTopShadow];
|