@synerise/ds-emoji-picker 1.1.5 → 1.2.1
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 +19 -0
- package/dist/EmojiList/EmojiList.d.ts +1 -1
- package/dist/EmojiList/EmojiList.js +34 -23
- package/dist/EmojiList/EmojiList.styles.d.ts +13 -1
- package/dist/EmojiList/EmojiList.styles.js +37 -6
- package/dist/EmojiList/EmojiList.types.d.ts +22 -1
- package/dist/EmojiList/EmojiList.utils.d.ts +2 -0
- package/dist/EmojiList/EmojiList.utils.js +9 -0
- package/dist/EmojiList/EmojiListItem.d.ts +3 -0
- package/dist/EmojiList/EmojiListItem.js +31 -0
- package/dist/EmojiPicker.const.d.ts +2 -0
- package/dist/EmojiPicker.const.js +2 -0
- package/dist/EmojiPicker.js +4 -1
- package/dist/EmojiPicker.types.d.ts +2 -1
- package/dist/hooks/useEmojiTranslations.js +4 -0
- package/dist/hooks/useMultipleItemsPerRow.d.ts +2 -0
- package/dist/hooks/useMultipleItemsPerRow.js +26 -0
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.2.1](https://github.com/Synerise/synerise-design/compare/@synerise/ds-emoji-picker@1.2.0...@synerise/ds-emoji-picker@1.2.1) (2025-05-26)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @synerise/ds-emoji-picker
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.2.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-emoji-picker@1.1.5...@synerise/ds-emoji-picker@1.2.0) (2025-05-19)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **emoji-picker:** changed list to virtualised list ([06e6f7a](https://github.com/Synerise/synerise-design/commit/06e6f7ab6f1bbef67adc8662888f35182828b2a4))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [1.1.5](https://github.com/Synerise/synerise-design/compare/@synerise/ds-emoji-picker@1.1.4...@synerise/ds-emoji-picker@1.1.5) (2025-05-07)
|
|
7
26
|
|
|
8
27
|
**Note:** Version bump only for package @synerise/ds-emoji-picker
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
2
|
-
import Divider from '@synerise/ds-divider';
|
|
3
|
-
import Scrollbar from '@synerise/ds-scrollbar';
|
|
1
|
+
import React, { useMemo, useRef } from 'react';
|
|
4
2
|
import { getEmojisByGroup } from 'unicode-emoji-utils';
|
|
3
|
+
import EmptyState, { EmptyStatesSize } from '@synerise/ds-empty-states';
|
|
4
|
+
import Scrollbar from '@synerise/ds-scrollbar';
|
|
5
|
+
import { SearchNoResultsL } from '@synerise/ds-icon';
|
|
5
6
|
import * as S from './EmojiList.styles';
|
|
6
7
|
import { useEmojiTranslations } from '../hooks/useEmojiTranslations';
|
|
8
|
+
import { useMultipleItemsPerRow } from '../hooks/useMultipleItemsPerRow';
|
|
9
|
+
import { ITEMS_PER_ROW, ITEM_SIZE } from '../EmojiPicker.const';
|
|
10
|
+
import { createItemData } from './EmojiList.utils';
|
|
11
|
+
import { EmojiListItem } from './EmojiListItem';
|
|
7
12
|
export var EmojiList = function EmojiList(_ref) {
|
|
8
13
|
var customTexts = _ref.texts,
|
|
9
14
|
onSelect = _ref.onSelect,
|
|
10
15
|
searchQuery = _ref.searchQuery;
|
|
11
16
|
var texts = useEmojiTranslations(customTexts);
|
|
17
|
+
var listRef = useRef(null);
|
|
12
18
|
var grouped = useMemo(function () {
|
|
13
19
|
return getEmojisByGroup('group');
|
|
14
20
|
}, []);
|
|
@@ -30,26 +36,31 @@ export var EmojiList = function EmojiList(_ref) {
|
|
|
30
36
|
});
|
|
31
37
|
return items;
|
|
32
38
|
}, [searchQuery, grouped, texts]);
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
var virtualListData = useMultipleItemsPerRow(filteredList, ITEMS_PER_ROW);
|
|
40
|
+
var itemData = createItemData(virtualListData, ITEM_SIZE, onSelect, ITEMS_PER_ROW);
|
|
41
|
+
var handleScroll = function handleScroll(_ref2) {
|
|
42
|
+
var currentTarget = _ref2.currentTarget;
|
|
43
|
+
var scrollTop = currentTarget.scrollTop;
|
|
44
|
+
if (listRef.current) {
|
|
45
|
+
listRef.current.scrollTo(scrollTop);
|
|
46
|
+
}
|
|
36
47
|
};
|
|
37
|
-
return /*#__PURE__*/React.createElement(Scrollbar, {
|
|
38
|
-
maxHeight: 330
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
return filteredList.length ? /*#__PURE__*/React.createElement(Scrollbar, {
|
|
49
|
+
maxHeight: 330,
|
|
50
|
+
onScroll: handleScroll
|
|
51
|
+
}, /*#__PURE__*/React.createElement(S.VirtualList, {
|
|
52
|
+
listHeight: 330,
|
|
53
|
+
ref: listRef,
|
|
54
|
+
height: 330,
|
|
55
|
+
itemCount: virtualListData.length,
|
|
56
|
+
itemData: itemData,
|
|
57
|
+
itemSize: ITEM_SIZE,
|
|
58
|
+
width: "100%"
|
|
59
|
+
}, function (props) {
|
|
60
|
+
return /*#__PURE__*/React.createElement(EmojiListItem, props);
|
|
61
|
+
})) : /*#__PURE__*/React.createElement(S.EmptyList, null, /*#__PURE__*/React.createElement(EmptyState, {
|
|
62
|
+
customIcon: /*#__PURE__*/React.createElement(SearchNoResultsL, null),
|
|
63
|
+
size: EmptyStatesSize.SMALL,
|
|
64
|
+
text: texts.empty
|
|
54
65
|
}));
|
|
55
66
|
};
|
|
@@ -1,3 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
2
|
+
import { FixedSizeList } from 'react-window';
|
|
3
|
+
export declare const EmojiItem: import("styled-components").StyledComponent<"div", any, {
|
|
4
|
+
itemsPerRow: number;
|
|
5
|
+
}, never>;
|
|
6
|
+
export declare const EmojiButton: import("styled-components").StyledComponent<(props: any) => React.JSX.Element, any, {}, never>;
|
|
7
|
+
export declare const EmptyList: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
3
8
|
export declare const EmojiCategoryWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
9
|
+
export declare const VirtualList: import("styled-components").StyledComponent<typeof FixedSizeList, any, {
|
|
10
|
+
listHeight: number;
|
|
11
|
+
}, never>;
|
|
12
|
+
export declare const ListRow: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
13
|
+
export declare const Title: import("styled-components").StyledComponent<"div", any, {
|
|
14
|
+
elementSize: string;
|
|
15
|
+
}, never>;
|
|
@@ -2,16 +2,47 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import Button from '@synerise/ds-button';
|
|
5
|
-
|
|
5
|
+
import { FixedSizeList } from 'react-window';
|
|
6
|
+
export var EmojiItem = styled.div.withConfig({
|
|
7
|
+
displayName: "EmojiListstyles__EmojiItem",
|
|
8
|
+
componentId: "sc-1yme2ir-0"
|
|
9
|
+
})(["display:flex;width:", "%;align-items:center;justify-content:center;"], function (props) {
|
|
10
|
+
return 100 / props.itemsPerRow;
|
|
11
|
+
});
|
|
12
|
+
export var EmojiButton = styled(function (props) {
|
|
6
13
|
return /*#__PURE__*/React.createElement(Button, _extends({}, props, {
|
|
7
14
|
type: "ghost",
|
|
8
15
|
mode: "single-icon"
|
|
9
16
|
}));
|
|
10
17
|
}).withConfig({
|
|
11
|
-
displayName: "
|
|
12
|
-
componentId: "sc-1yme2ir-
|
|
13
|
-
})(["font-size:
|
|
18
|
+
displayName: "EmojiListstyles__EmojiButton",
|
|
19
|
+
componentId: "sc-1yme2ir-1"
|
|
20
|
+
})(["font-size:24px;display:flex;align-items:center;cursor:pointer;"]);
|
|
21
|
+
export var EmptyList = styled.div.withConfig({
|
|
22
|
+
displayName: "EmojiListstyles__EmptyList",
|
|
23
|
+
componentId: "sc-1yme2ir-2"
|
|
24
|
+
})(["padding:12px;"]);
|
|
14
25
|
export var EmojiCategoryWrapper = styled.div.withConfig({
|
|
15
26
|
displayName: "EmojiListstyles__EmojiCategoryWrapper",
|
|
16
|
-
componentId: "sc-1yme2ir-
|
|
17
|
-
})(["display:flex;gap:4px;flex-wrap:wrap;"]);
|
|
27
|
+
componentId: "sc-1yme2ir-3"
|
|
28
|
+
})(["display:flex;gap:4px;flex-wrap:wrap;"]);
|
|
29
|
+
export var VirtualList = styled(FixedSizeList).withConfig({
|
|
30
|
+
displayName: "EmojiListstyles__VirtualList",
|
|
31
|
+
componentId: "sc-1yme2ir-4"
|
|
32
|
+
})(["max-height:", "px;height:auto !important;overflow-x:unset !important;overflow-y:unset !important;"], function (props) {
|
|
33
|
+
return props.listHeight;
|
|
34
|
+
});
|
|
35
|
+
export var ListRow = styled.div.withConfig({
|
|
36
|
+
displayName: "EmojiListstyles__ListRow",
|
|
37
|
+
componentId: "sc-1yme2ir-5"
|
|
38
|
+
})(["display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;box-sizing:border-box;width:100%;height:100%;max-width:100%;"]);
|
|
39
|
+
export var Title = styled.div.withConfig({
|
|
40
|
+
displayName: "EmojiListstyles__Title",
|
|
41
|
+
componentId: "sc-1yme2ir-6"
|
|
42
|
+
})(["font-size:10px;line-height:1.6;font-weight:500;text-transform:uppercase;color:", ";padding:0 12px;flex-basis:100%;height:", ";line-height:", ";"], function (props) {
|
|
43
|
+
return props.theme.palette['grey-500'];
|
|
44
|
+
}, function (props) {
|
|
45
|
+
return props.elementSize;
|
|
46
|
+
}, function (props) {
|
|
47
|
+
return props.elementSize;
|
|
48
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import type { Emoji } from 'unicode-emoji-utils';
|
|
3
3
|
export type EmojiListTexts = {
|
|
4
4
|
'smileys-emotion': ReactNode;
|
|
@@ -20,3 +20,24 @@ export type EmojiCategory = {
|
|
|
20
20
|
title: ReactNode;
|
|
21
21
|
emojis: Emoji[];
|
|
22
22
|
};
|
|
23
|
+
export type RowItemProps = {
|
|
24
|
+
data: ListItemData;
|
|
25
|
+
index: number;
|
|
26
|
+
style: CSSProperties;
|
|
27
|
+
};
|
|
28
|
+
export type TitleItem = {
|
|
29
|
+
title: ReactNode;
|
|
30
|
+
};
|
|
31
|
+
export type EmojiVirtualListItem = Emoji[] | TitleItem[];
|
|
32
|
+
export type ListItemData = {
|
|
33
|
+
items: EmojiVirtualListItem[];
|
|
34
|
+
onSelect?: (emoji: Emoji) => void;
|
|
35
|
+
itemsPerRow: number;
|
|
36
|
+
elementSize: number;
|
|
37
|
+
};
|
|
38
|
+
export type ListItemProps = {
|
|
39
|
+
element: Emoji;
|
|
40
|
+
index: number;
|
|
41
|
+
itemsPerRow: number;
|
|
42
|
+
onSelect: (emoji: Emoji) => void;
|
|
43
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { areEqual } from 'react-window';
|
|
3
|
+
import * as S from './EmojiList.styles';
|
|
4
|
+
var isTitle = function isTitle(item) {
|
|
5
|
+
return item[0] && 'title' in item[0];
|
|
6
|
+
};
|
|
7
|
+
export var EmojiListItem = /*#__PURE__*/memo(function (_ref) {
|
|
8
|
+
var data = _ref.data,
|
|
9
|
+
index = _ref.index,
|
|
10
|
+
style = _ref.style;
|
|
11
|
+
var elementSize = data.elementSize,
|
|
12
|
+
itemsPerRow = data.itemsPerRow,
|
|
13
|
+
onSelect = data.onSelect,
|
|
14
|
+
items = data.items;
|
|
15
|
+
var rowItems = items[index];
|
|
16
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
17
|
+
style: style
|
|
18
|
+
}, /*#__PURE__*/React.createElement(S.ListRow, null, isTitle(rowItems) ? /*#__PURE__*/React.createElement(S.Title, {
|
|
19
|
+
elementSize: elementSize + "px"
|
|
20
|
+
}, rowItems[0].title) : rowItems.map(function (item) {
|
|
21
|
+
return /*#__PURE__*/React.createElement(S.EmojiItem, {
|
|
22
|
+
onClick: function onClick() {
|
|
23
|
+
return onSelect && onSelect(item);
|
|
24
|
+
},
|
|
25
|
+
itemsPerRow: itemsPerRow,
|
|
26
|
+
key: item.emoji
|
|
27
|
+
}, /*#__PURE__*/React.createElement(S.EmojiButton, {
|
|
28
|
+
"data-testid": "ds-emoji-item"
|
|
29
|
+
}, item.emoji));
|
|
30
|
+
})));
|
|
31
|
+
}, areEqual);
|
package/dist/EmojiPicker.js
CHANGED
|
@@ -31,7 +31,10 @@ export var EmojiPicker = function EmojiPicker(_ref) {
|
|
|
31
31
|
placement: "bottomRight"
|
|
32
32
|
}, dropdownProps, {
|
|
33
33
|
overlay: /*#__PURE__*/React.createElement(S.Overlay, {
|
|
34
|
-
ref: ref
|
|
34
|
+
ref: ref,
|
|
35
|
+
onClick: function onClick(event) {
|
|
36
|
+
return event.stopPropagation();
|
|
37
|
+
}
|
|
35
38
|
}, /*#__PURE__*/React.createElement(EmojiOverlay, {
|
|
36
39
|
onSelect: function onSelect(val) {
|
|
37
40
|
closeOnSelect && toggleOpen(false);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { ReactElement } from 'react';
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
2
|
import type { DropdownProps } from '@synerise/ds-dropdown';
|
|
3
3
|
import type { Emoji } from 'unicode-emoji-utils';
|
|
4
4
|
import type { EmojiListTexts } from './EmojiList/EmojiList.types';
|
|
5
5
|
export type EmojiPickerTexts = EmojiListTexts & {
|
|
6
6
|
placeholder: string;
|
|
7
|
+
empty: ReactNode;
|
|
7
8
|
};
|
|
8
9
|
export type EmojiPickerProps = {
|
|
9
10
|
children?: ReactElement;
|
|
@@ -45,6 +45,10 @@ export var useEmojiTranslations = function useEmojiTranslations(texts) {
|
|
|
45
45
|
placeholder: formatMessage({
|
|
46
46
|
id: 'DS.ICON-PICKER.PLACEHOLDER',
|
|
47
47
|
defaultMessage: 'Search'
|
|
48
|
+
}),
|
|
49
|
+
empty: /*#__PURE__*/React.createElement(FormattedMessage, {
|
|
50
|
+
id: "DS.ICON-PICKER.NO-MATCHES",
|
|
51
|
+
defaultMessage: "No emojis found"
|
|
48
52
|
})
|
|
49
53
|
}, texts || {});
|
|
50
54
|
}, [texts, formatMessage]);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
export var useMultipleItemsPerRow = function useMultipleItemsPerRow(data, itemsPerRow) {
|
|
3
|
+
var groupedData = useMemo(function () {
|
|
4
|
+
return data.reduce(function (flatItemsAndCategories, group) {
|
|
5
|
+
var title = group.title,
|
|
6
|
+
emojis = group.emojis;
|
|
7
|
+
flatItemsAndCategories.push([{
|
|
8
|
+
title: title
|
|
9
|
+
}]);
|
|
10
|
+
var groupItemsLength = emojis.length;
|
|
11
|
+
var rowCount = Math.ceil(groupItemsLength / itemsPerRow);
|
|
12
|
+
for (var i = 0; i < rowCount; i += 1) {
|
|
13
|
+
var rowItems = [];
|
|
14
|
+
for (var j = 0; j < itemsPerRow; j += 1) {
|
|
15
|
+
var idx = itemsPerRow * i + j;
|
|
16
|
+
if (idx < groupItemsLength) {
|
|
17
|
+
rowItems.push(emojis[idx]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
flatItemsAndCategories.push(rowItems);
|
|
21
|
+
}
|
|
22
|
+
return flatItemsAndCategories;
|
|
23
|
+
}, []);
|
|
24
|
+
}, [data, itemsPerRow]);
|
|
25
|
+
return groupedData;
|
|
26
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synerise/ds-emoji-picker",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "EmojiPicker UI Component for the Synerise Design System",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": "Synerise/synerise-design",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
],
|
|
35
35
|
"types": "dist/index.d.ts",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@synerise/ds-button": "^1.
|
|
38
|
-
"@synerise/ds-divider": "^1.0.
|
|
39
|
-
"@synerise/ds-dropdown": "^1.0.
|
|
40
|
-
"@synerise/ds-icon": "^1.
|
|
41
|
-
"@synerise/ds-scrollbar": "^1.0.
|
|
42
|
-
"@synerise/ds-utils": "^1.1.
|
|
37
|
+
"@synerise/ds-button": "^1.3.1",
|
|
38
|
+
"@synerise/ds-divider": "^1.0.9",
|
|
39
|
+
"@synerise/ds-dropdown": "^1.0.9",
|
|
40
|
+
"@synerise/ds-icon": "^1.5.1",
|
|
41
|
+
"@synerise/ds-scrollbar": "^1.0.9",
|
|
42
|
+
"@synerise/ds-utils": "^1.1.1",
|
|
43
43
|
"unicode-emoji-utils": "^1.2.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"react-intl": ">=3.12.0 <= 6.8",
|
|
49
49
|
"styled-components": "^5.3.3"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "9e9cc54e3690b4d51323f91c81b3b79305984da6"
|
|
52
52
|
}
|