@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.
Files changed (125) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/afm-jira/tsconfig.json +3 -0
  4. package/afm-post-office/tsconfig.json +3 -0
  5. package/dist/cjs/components/compiled/common/EmojiActions.js +1 -1
  6. package/dist/cjs/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
  7. package/dist/cjs/components/compiled/common/EmojiPreviewComponent.js +1 -1
  8. package/dist/cjs/components/compiled/picker/CategorySelector.compiled.css +24 -0
  9. package/dist/cjs/components/compiled/picker/CategorySelector.js +161 -0
  10. package/dist/cjs/components/compiled/picker/EmojiPicker.compiled.css +12 -0
  11. package/dist/cjs/components/compiled/picker/EmojiPicker.js +109 -0
  12. package/dist/cjs/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
  13. package/dist/cjs/components/compiled/picker/EmojiPickerCategoryHeading.js +43 -0
  14. package/dist/cjs/components/compiled/picker/EmojiPickerComponent.compiled.css +20 -0
  15. package/dist/cjs/components/compiled/picker/EmojiPickerComponent.js +574 -0
  16. package/dist/cjs/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
  17. package/dist/cjs/components/compiled/picker/EmojiPickerEmojiRow.js +76 -0
  18. package/dist/cjs/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
  19. package/dist/cjs/components/compiled/picker/EmojiPickerFooter.js +33 -0
  20. package/dist/cjs/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
  21. package/dist/cjs/components/compiled/picker/EmojiPickerListSearch.js +93 -0
  22. package/dist/cjs/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
  23. package/dist/cjs/components/compiled/picker/EmojiPickerTabPanel.js +60 -0
  24. package/dist/cjs/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
  25. package/dist/cjs/components/compiled/picker/EmojiPickerVirtualItems.js +86 -0
  26. package/dist/cjs/components/compiled/picker/VirtualList.compiled.css +10 -0
  27. package/dist/cjs/components/compiled/picker/VirtualList.js +303 -0
  28. package/dist/cjs/components/picker/EmojiPickerFooter.js +0 -2
  29. package/dist/cjs/components/picker/EmojiPickerList.js +219 -145
  30. package/dist/cjs/components/picker/EmojiPickerTabPanel.js +67 -0
  31. package/dist/cjs/components/picker/styles.js +1 -10
  32. package/dist/cjs/index.js +4 -6
  33. package/dist/cjs/picker.js +5 -7
  34. package/dist/cjs/util/analytics/analytics.js +1 -1
  35. package/dist/es2019/components/compiled/common/EmojiActions.js +1 -1
  36. package/dist/es2019/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
  37. package/dist/es2019/components/compiled/common/EmojiPreviewComponent.js +1 -1
  38. package/dist/es2019/components/compiled/picker/CategorySelector.compiled.css +24 -0
  39. package/dist/es2019/components/compiled/picker/CategorySelector.js +136 -0
  40. package/dist/es2019/components/compiled/picker/EmojiPicker.compiled.css +12 -0
  41. package/dist/es2019/components/compiled/picker/EmojiPicker.js +67 -0
  42. package/dist/es2019/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
  43. package/dist/es2019/components/compiled/picker/EmojiPickerCategoryHeading.js +30 -0
  44. package/dist/es2019/components/compiled/picker/EmojiPickerComponent.compiled.css +19 -0
  45. package/dist/es2019/components/compiled/picker/EmojiPickerComponent.js +506 -0
  46. package/dist/es2019/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
  47. package/dist/es2019/components/compiled/picker/EmojiPickerEmojiRow.js +69 -0
  48. package/dist/es2019/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
  49. package/dist/es2019/components/compiled/picker/EmojiPickerFooter.js +19 -0
  50. package/dist/es2019/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
  51. package/dist/es2019/components/compiled/picker/EmojiPickerListSearch.js +79 -0
  52. package/dist/es2019/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
  53. package/dist/es2019/components/compiled/picker/EmojiPickerTabPanel.js +39 -0
  54. package/dist/es2019/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
  55. package/dist/es2019/components/compiled/picker/EmojiPickerVirtualItems.js +51 -0
  56. package/dist/es2019/components/compiled/picker/VirtualList.compiled.css +10 -0
  57. package/dist/es2019/components/compiled/picker/VirtualList.js +288 -0
  58. package/dist/es2019/components/picker/EmojiPickerFooter.js +1 -1
  59. package/dist/es2019/components/picker/EmojiPickerList.js +186 -114
  60. package/dist/es2019/components/picker/EmojiPickerTabPanel.js +48 -0
  61. package/dist/es2019/components/picker/styles.js +0 -9
  62. package/dist/es2019/index.js +2 -1
  63. package/dist/es2019/picker.js +5 -1
  64. package/dist/es2019/util/analytics/analytics.js +1 -1
  65. package/dist/esm/components/compiled/common/EmojiActions.js +1 -1
  66. package/dist/esm/components/compiled/common/EmojiPreviewComponent.compiled.css +0 -1
  67. package/dist/esm/components/compiled/common/EmojiPreviewComponent.js +1 -1
  68. package/dist/esm/components/compiled/picker/CategorySelector.compiled.css +24 -0
  69. package/dist/esm/components/compiled/picker/CategorySelector.js +151 -0
  70. package/dist/esm/components/compiled/picker/EmojiPicker.compiled.css +12 -0
  71. package/dist/esm/components/compiled/picker/EmojiPicker.js +97 -0
  72. package/dist/esm/components/compiled/picker/EmojiPickerCategoryHeading.compiled.css +9 -0
  73. package/dist/esm/components/compiled/picker/EmojiPickerCategoryHeading.js +34 -0
  74. package/dist/esm/components/compiled/picker/EmojiPickerComponent.compiled.css +20 -0
  75. package/dist/esm/components/compiled/picker/EmojiPickerComponent.js +564 -0
  76. package/dist/esm/components/compiled/picker/EmojiPickerEmojiRow.compiled.css +35 -0
  77. package/dist/esm/components/compiled/picker/EmojiPickerEmojiRow.js +66 -0
  78. package/dist/esm/components/compiled/picker/EmojiPickerFooter.compiled.css +5 -0
  79. package/dist/esm/components/compiled/picker/EmojiPickerFooter.js +24 -0
  80. package/dist/esm/components/compiled/picker/EmojiPickerListSearch.compiled.css +23 -0
  81. package/dist/esm/components/compiled/picker/EmojiPickerListSearch.js +83 -0
  82. package/dist/esm/components/compiled/picker/EmojiPickerTabPanel.compiled.css +6 -0
  83. package/dist/esm/components/compiled/picker/EmojiPickerTabPanel.js +50 -0
  84. package/dist/esm/components/compiled/picker/EmojiPickerVirtualItems.compiled.css +8 -0
  85. package/dist/esm/components/compiled/picker/EmojiPickerVirtualItems.js +76 -0
  86. package/dist/esm/components/compiled/picker/VirtualList.compiled.css +10 -0
  87. package/dist/esm/components/compiled/picker/VirtualList.js +293 -0
  88. package/dist/esm/components/picker/EmojiPickerFooter.js +1 -1
  89. package/dist/esm/components/picker/EmojiPickerList.js +219 -147
  90. package/dist/esm/components/picker/EmojiPickerTabPanel.js +59 -0
  91. package/dist/esm/components/picker/styles.js +0 -9
  92. package/dist/esm/index.js +2 -1
  93. package/dist/esm/picker.js +5 -1
  94. package/dist/esm/util/analytics/analytics.js +1 -1
  95. package/dist/types/components/compiled/picker/CategorySelector.d.ts +17 -0
  96. package/dist/types/components/compiled/picker/EmojiPicker.d.ts +44 -0
  97. package/dist/types/components/compiled/picker/EmojiPickerCategoryHeading.d.ts +13 -0
  98. package/dist/types/components/compiled/picker/EmojiPickerComponent.d.ts +24 -0
  99. package/dist/types/components/compiled/picker/EmojiPickerEmojiRow.d.ts +17 -0
  100. package/dist/types/components/compiled/picker/EmojiPickerFooter.d.ts +8 -0
  101. package/dist/types/components/compiled/picker/EmojiPickerListSearch.d.ts +11 -0
  102. package/dist/types/components/compiled/picker/EmojiPickerTabPanel.d.ts +21 -0
  103. package/dist/types/components/compiled/picker/EmojiPickerVirtualItems.d.ts +35 -0
  104. package/dist/types/components/compiled/picker/VirtualList.d.ts +42 -0
  105. package/dist/types/components/picker/EmojiPickerList.d.ts +1 -6
  106. package/dist/types/components/picker/EmojiPickerTabPanel.d.ts +21 -0
  107. package/dist/types/components/picker/styles.d.ts +0 -1
  108. package/dist/types/index.d.ts +2 -1
  109. package/dist/types/picker.d.ts +3 -1
  110. package/dist/types-ts4.5/components/compiled/picker/CategorySelector.d.ts +17 -0
  111. package/dist/types-ts4.5/components/compiled/picker/EmojiPicker.d.ts +44 -0
  112. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerCategoryHeading.d.ts +13 -0
  113. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerComponent.d.ts +24 -0
  114. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerEmojiRow.d.ts +17 -0
  115. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerFooter.d.ts +8 -0
  116. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerListSearch.d.ts +11 -0
  117. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerTabPanel.d.ts +21 -0
  118. package/dist/types-ts4.5/components/compiled/picker/EmojiPickerVirtualItems.d.ts +35 -0
  119. package/dist/types-ts4.5/components/compiled/picker/VirtualList.d.ts +42 -0
  120. package/dist/types-ts4.5/components/picker/EmojiPickerList.d.ts +1 -6
  121. package/dist/types-ts4.5/components/picker/EmojiPickerTabPanel.d.ts +21 -0
  122. package/dist/types-ts4.5/components/picker/styles.d.ts +0 -1
  123. package/dist/types-ts4.5/index.d.ts +2 -1
  124. package/dist/types-ts4.5/picker.d.ts +3 -1
  125. 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,6 @@
1
+ ._16jlkb7n{flex-grow:1}
2
+ ._1e0c1txw{display:flex}
3
+ ._1o9zkb7n{flex-shrink:1}
4
+ ._2lx21bp4{flex-direction:column}
5
+ ._4t3iidpf{height:0}
6
+ ._i0dl1wug{flex-basis:auto}
@@ -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,8 @@
1
+ ._1bah1h6o{justify-content:center}
2
+ ._1bsb1osq{width:100%}
3
+ ._1e0c1txw{display:flex}
4
+ ._1t3b1wug >div{flex-basis:auto}
5
+ ._4cvr1h6o{align-items:center}
6
+ ._4t3i1w81{height:150px}
7
+ ._nphsidpf >div{flex-grow:0}
8
+ ._t1edidpf >div{flex-shrink:0}
@@ -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'; // ED-26865: use compiled EmojiPreviewComponent when migrating picker to compiled css
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];