@fibery/ui-kit 1.22.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/design-system.ts +2 -0
- package/src/emoji-picker/app-icon-picker.tsx +21 -15
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +9 -11
- package/src/emoji-picker/emoji-picker-preview-footer.tsx +94 -0
- package/src/emoji-picker/emoji-picker.tsx +3 -28
- package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
- package/src/emoji-picker/primitives/category-label.tsx +42 -0
- package/src/emoji-picker/primitives/content.tsx +15 -3
- package/src/emoji-picker/primitives/footer.tsx +4 -2
- package/src/emoji-picker/primitives/grid-item.tsx +73 -0
- package/src/emoji-picker/primitives/grid.tsx +332 -76
- package/src/emoji-picker/primitives/preview-provider.tsx +27 -0
- package/src/emoji-picker/primitives/root.tsx +8 -5
- package/src/emoji-picker/primitives/search.tsx +50 -6
- package/src/emoji-picker/stores/emoji-data-store.tsx +13 -10
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +4 -2
- package/src/emoji-picker/stores/static-emoji-data-store.tsx +11 -6
- package/src/lists/list-row-surface.tsx +8 -0
- package/src/select/index.tsx +5 -0
- package/src/emoji-picker/primitives/category.tsx +0 -177
- package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +0 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"files": [
|
|
@@ -66,12 +66,13 @@
|
|
|
66
66
|
"react-popper": "2.3.0",
|
|
67
67
|
"react-select": "5.3.2",
|
|
68
68
|
"react-select-country-list": "2.2.1",
|
|
69
|
+
"react-virtuoso": "4.6.0",
|
|
69
70
|
"react-windowed-select": "5.0.0",
|
|
70
71
|
"screenfull": "6.0.1",
|
|
71
72
|
"ua-parser-js": "0.7.24",
|
|
72
|
-
"@fibery/
|
|
73
|
+
"@fibery/emoji-data": "2.3.0",
|
|
73
74
|
"@fibery/helpers": "1.2.0",
|
|
74
|
-
"@fibery/
|
|
75
|
+
"@fibery/react": "1.3.0"
|
|
75
76
|
},
|
|
76
77
|
"peerDependencies": {
|
|
77
78
|
"react": "^18.2.0",
|
package/src/design-system.ts
CHANGED
|
@@ -746,6 +746,8 @@ export const spaceNestedTreeInterval = 0;
|
|
|
746
746
|
export const layout = {
|
|
747
747
|
logoSize: 16,
|
|
748
748
|
menuDefaultWidth: 243,
|
|
749
|
+
desktopToolbarHeight: 32,
|
|
750
|
+
desktopMenuMinWidth: 160,
|
|
749
751
|
menuMinWidth: 47, //TODO: make dependency to itemHeight
|
|
750
752
|
menuMaxWidth: 480,
|
|
751
753
|
menuItemMinWidth: 80,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {CustomEmoji, EmojiItem} from "@fibery/emoji-data";
|
|
2
|
-
import {
|
|
2
|
+
import {useCallback} from "react";
|
|
3
3
|
import {cardTypeColors, getIconColor} from "../design-system";
|
|
4
|
+
import {useThemeMode} from "../theme-provider";
|
|
4
5
|
import {$TSFixMe} from "../tsfixme";
|
|
5
|
-
import {EmojiPickerContentWithColor} from "./emoji-picker-content-with-color";
|
|
6
|
+
import {EmojiPickerContentWithColor, EmojiPickerContentWithColorProps} from "./emoji-picker-content-with-color";
|
|
6
7
|
import {EmojiPickerContent} from "./primitives/content";
|
|
7
8
|
import {EmojiPickerRoot} from "./primitives/root";
|
|
8
9
|
import {LazyIconDataStore} from "./stores/lazy-icon-data-store";
|
|
@@ -28,6 +29,23 @@ export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
|
28
29
|
}) => {
|
|
29
30
|
const themeMode = useThemeMode();
|
|
30
31
|
|
|
32
|
+
const renderEmoji = useCallback<NonNullable<EmojiPickerContentWithColorProps["renderEmoji"]>>(
|
|
33
|
+
({emoji}) => (
|
|
34
|
+
<svg
|
|
35
|
+
style={{
|
|
36
|
+
display: "block",
|
|
37
|
+
width: 20,
|
|
38
|
+
height: 20,
|
|
39
|
+
fill: color ? getIconColor(themeMode, color) : undefined,
|
|
40
|
+
}}
|
|
41
|
+
viewBox="0 0 24 24"
|
|
42
|
+
>
|
|
43
|
+
<use href={(emoji as CustomEmoji).imageUrl} />
|
|
44
|
+
</svg>
|
|
45
|
+
),
|
|
46
|
+
[color, themeMode]
|
|
47
|
+
);
|
|
48
|
+
|
|
31
49
|
return (
|
|
32
50
|
<EmojiPickerRoot i18n={i18n} onEmojiSelect={onSelect}>
|
|
33
51
|
<EmojiPickerContent emojiHoverColor={color ? getHoverColor?.(color) : undefined} emojiSize={20}>
|
|
@@ -38,19 +56,7 @@ export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
|
38
56
|
getHoverColor={getHoverColor}
|
|
39
57
|
onColorSelect={onColorSelect}
|
|
40
58
|
searchAutofocus={autoFocus}
|
|
41
|
-
renderEmoji={
|
|
42
|
-
<svg
|
|
43
|
-
style={{
|
|
44
|
-
display: "block",
|
|
45
|
-
width: 20,
|
|
46
|
-
height: 20,
|
|
47
|
-
fill: color ? getIconColor(themeMode, color) : undefined,
|
|
48
|
-
}}
|
|
49
|
-
viewBox="0 0 24 24"
|
|
50
|
-
>
|
|
51
|
-
<use href={(emoji as CustomEmoji).imageUrl} />
|
|
52
|
-
</svg>
|
|
53
|
-
)}
|
|
59
|
+
renderEmoji={renderEmoji}
|
|
54
60
|
/>
|
|
55
61
|
</LazyIconDataStore>
|
|
56
62
|
</EmojiPickerContent>
|
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
import {css
|
|
2
|
-
import {useState} from "react";
|
|
1
|
+
import {css} from "@linaria/core";
|
|
2
|
+
import {useState, useRef} from "react";
|
|
3
3
|
import {IconButton} from "../button/icon-button";
|
|
4
4
|
import {CollapsibleContent, CollapsibleRoot, CollapsibleTrigger} from "../collapsible";
|
|
5
5
|
import {ColorPicker} from "../color-picker";
|
|
6
|
-
import {useThemeMode} from "../theme-provider";
|
|
7
6
|
import {getIconColor, space} from "../design-system";
|
|
8
7
|
import ColorCoding from "../icons/react/ColorCoding";
|
|
9
8
|
import ColorCodingFilled from "../icons/react/ColorCodingFilled";
|
|
9
|
+
import {useThemeMode} from "../theme-provider";
|
|
10
|
+
import {Tooltip} from "../tooltip";
|
|
10
11
|
import {$TSFixMe} from "../tsfixme";
|
|
11
|
-
import {EmojiPickerGrid, EmojiPickerGridProps} from "./primitives/grid";
|
|
12
|
+
import {EmojiPickerGrid, type EmojiPickerGridHandle, EmojiPickerGridProps} from "./primitives/grid";
|
|
12
13
|
import {EmojiPickerHeader} from "./primitives/header";
|
|
13
14
|
import {EmojiPickerSearch} from "./primitives/search";
|
|
14
|
-
import {Tooltip} from "../tooltip";
|
|
15
15
|
|
|
16
16
|
const colorPickerWrapperCss = css`
|
|
17
17
|
padding-top: ${space.s12}px;
|
|
18
18
|
`;
|
|
19
19
|
|
|
20
|
-
const disableScrollCss = css`
|
|
21
|
-
overflow-y: hidden;
|
|
22
|
-
`;
|
|
23
|
-
|
|
24
20
|
type ColorPickerCollapsibleTrigger = {opened: boolean; color?: string};
|
|
25
21
|
|
|
26
22
|
const ColorPickerCollapsibleTrigger: React.FC<ColorPickerCollapsibleTrigger> = ({opened, color}) => {
|
|
@@ -50,7 +46,7 @@ const ColorPickerCollapsibleTrigger: React.FC<ColorPickerCollapsibleTrigger> = (
|
|
|
50
46
|
};
|
|
51
47
|
|
|
52
48
|
const collapsibleWrapperCss = css`
|
|
53
|
-
max-height:
|
|
49
|
+
max-height: 308px; // search + emoji grid
|
|
54
50
|
overflow: hidden;
|
|
55
51
|
`;
|
|
56
52
|
|
|
@@ -74,6 +70,7 @@ export const EmojiPickerContentWithColor: React.FC<EmojiPickerContentWithColorPr
|
|
|
74
70
|
renderEmoji,
|
|
75
71
|
}) => {
|
|
76
72
|
const [colorOpened, setColorOpened] = useState(false);
|
|
73
|
+
const gridRef = useRef<EmojiPickerGridHandle>(null);
|
|
77
74
|
|
|
78
75
|
const showColorPicker = Boolean(onColorSelect);
|
|
79
76
|
|
|
@@ -87,6 +84,7 @@ export const EmojiPickerContentWithColor: React.FC<EmojiPickerContentWithColorPr
|
|
|
87
84
|
<EmojiPickerHeader>
|
|
88
85
|
<EmojiPickerSearch
|
|
89
86
|
searchRef={searchRef}
|
|
87
|
+
gridRef={gridRef}
|
|
90
88
|
autoFocus={searchAutofocus}
|
|
91
89
|
extraAction={showColorPicker ? <ColorPickerCollapsibleTrigger opened={colorOpened} color={color} /> : null}
|
|
92
90
|
/>
|
|
@@ -104,7 +102,7 @@ export const EmojiPickerContentWithColor: React.FC<EmojiPickerContentWithColorPr
|
|
|
104
102
|
) : null}
|
|
105
103
|
</EmojiPickerHeader>
|
|
106
104
|
|
|
107
|
-
<EmojiPickerGrid
|
|
105
|
+
<EmojiPickerGrid ref={gridRef} disableScroll={colorOpened} renderEmoji={renderEmoji} />
|
|
108
106
|
</CollapsibleRoot>
|
|
109
107
|
);
|
|
110
108
|
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type {EmojiItem} from "@fibery/emoji-data";
|
|
2
|
+
import {measureScrollbar} from "@fibery/helpers/utils/measure-scrollbar";
|
|
3
|
+
import {css} from "@linaria/core";
|
|
4
|
+
import {Button} from "../button";
|
|
5
|
+
import {fontFamily, space, themeVars, typeSizes} from "../design-system";
|
|
6
|
+
import {Emoji} from "./primitives/emoji";
|
|
7
|
+
import {EmojiPickerFooter} from "./primitives/footer";
|
|
8
|
+
import {useEmojiPreview} from "./primitives/preview-provider";
|
|
9
|
+
import {useEmojiPickerCtx} from "./primitives/root";
|
|
10
|
+
import {useEmojiSkin} from "./primitives/skin-provider";
|
|
11
|
+
import {EmojiPickerSkinTone} from "./primitives/skin-tone";
|
|
12
|
+
|
|
13
|
+
const previewCss = css`
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: ${space.s8}px;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
`;
|
|
19
|
+
const previewTitleWrapperCss = css`
|
|
20
|
+
max-width: 230px;
|
|
21
|
+
`;
|
|
22
|
+
const previewTitleCss = css`
|
|
23
|
+
font-family: ${fontFamily};
|
|
24
|
+
font-size: ${typeSizes[5]}px;
|
|
25
|
+
line-height: 1.25;
|
|
26
|
+
color: ${themeVars.textColor};
|
|
27
|
+
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
text-overflow: ellipsis;
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
`;
|
|
32
|
+
const previewSubtitleCss = css`
|
|
33
|
+
font-family: ${fontFamily};
|
|
34
|
+
letter-spacing: 0.5px;
|
|
35
|
+
font-size: ${typeSizes[6]}px;
|
|
36
|
+
line-height: 1.25;
|
|
37
|
+
color: ${themeVars.accentTextColor};
|
|
38
|
+
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
text-overflow: ellipsis;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const EmojiPreview: React.FC<{emoji: EmojiItem}> = ({emoji}) => {
|
|
45
|
+
const emojiPickerCtx = useEmojiPickerCtx();
|
|
46
|
+
const skin = useEmojiSkin();
|
|
47
|
+
|
|
48
|
+
const title = emoji.name;
|
|
49
|
+
const subTitle = emoji.shortNames.map((short) => `:${short}:`).join(" ");
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className={previewCss}>
|
|
53
|
+
<Emoji emoji={emoji.id} size={24} version={emojiPickerCtx.version} skin={skin} native={emojiPickerCtx.native} />
|
|
54
|
+
<div className={previewTitleWrapperCss}>
|
|
55
|
+
<div className={previewTitleCss}>{title}</div>
|
|
56
|
+
<div className={previewSubtitleCss}>{subTitle}</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const EmojiPickerPreviewFooter: React.FC<{
|
|
63
|
+
onAddCustomEmoji?: () => void;
|
|
64
|
+
showSkinTones?: boolean;
|
|
65
|
+
}> = ({onAddCustomEmoji, showSkinTones}) => {
|
|
66
|
+
const emojiPreview = useEmojiPreview();
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<EmojiPickerFooter>
|
|
70
|
+
{emojiPreview ? (
|
|
71
|
+
<EmojiPreview emoji={emojiPreview.emoji} />
|
|
72
|
+
) : onAddCustomEmoji ? (
|
|
73
|
+
<Button size=":button-size/small" onClick={onAddCustomEmoji}>
|
|
74
|
+
Add Emoji
|
|
75
|
+
</Button>
|
|
76
|
+
) : null}
|
|
77
|
+
|
|
78
|
+
{showSkinTones ? (
|
|
79
|
+
<div
|
|
80
|
+
className={css`
|
|
81
|
+
position: absolute;
|
|
82
|
+
top: 4px;
|
|
83
|
+
right: ${space.s12}px;
|
|
84
|
+
`}
|
|
85
|
+
style={{
|
|
86
|
+
right: space.s12 + measureScrollbar(),
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<EmojiPickerSkinTone />
|
|
90
|
+
</div>
|
|
91
|
+
) : null}
|
|
92
|
+
</EmojiPickerFooter>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import {EmojiItem} from "@fibery/emoji-data";
|
|
2
|
-
import {
|
|
3
|
-
import {Button} from "../button";
|
|
4
|
-
import {cardTypeColors, space} from "../design-system";
|
|
2
|
+
import {cardTypeColors} from "../design-system";
|
|
5
3
|
import {$TSFixMe} from "../tsfixme";
|
|
6
4
|
import {EmojiPickerContentWithColor} from "./emoji-picker-content-with-color";
|
|
5
|
+
import {EmojiPickerPreviewFooter} from "./emoji-picker-preview-footer";
|
|
7
6
|
import {EmojiPickerContent} from "./primitives/content";
|
|
8
|
-
import {EmojiPickerFooter} from "./primitives/footer";
|
|
9
7
|
import {EmojiPickerRoot} from "./primitives/root";
|
|
10
|
-
import {EmojiPickerSkinTone} from "./primitives/skin-tone";
|
|
11
|
-
import {measureScrollbar} from "@fibery/helpers/utils/measure-scrollbar";
|
|
12
8
|
|
|
13
9
|
const i18n = {search: "Search emoji..."};
|
|
14
10
|
|
|
@@ -49,28 +45,7 @@ export const EmojiPicker: React.FC<EmojiPickerProps> = ({
|
|
|
49
45
|
/>
|
|
50
46
|
|
|
51
47
|
{showFooter ? (
|
|
52
|
-
<
|
|
53
|
-
{onAddCustomEmoji ? (
|
|
54
|
-
<Button size=":button-size/small" onClick={onAddCustomEmoji}>
|
|
55
|
-
Add Emoji
|
|
56
|
-
</Button>
|
|
57
|
-
) : null}
|
|
58
|
-
|
|
59
|
-
{showSkinTones ? (
|
|
60
|
-
<div
|
|
61
|
-
className={css`
|
|
62
|
-
position: absolute;
|
|
63
|
-
top: 4px;
|
|
64
|
-
right: ${space.s12}px;
|
|
65
|
-
`}
|
|
66
|
-
style={{
|
|
67
|
-
right: space.s12 + measureScrollbar(),
|
|
68
|
-
}}
|
|
69
|
-
>
|
|
70
|
-
<EmojiPickerSkinTone />
|
|
71
|
-
</div>
|
|
72
|
-
) : null}
|
|
73
|
-
</EmojiPickerFooter>
|
|
48
|
+
<EmojiPickerPreviewFooter onAddCustomEmoji={onAddCustomEmoji} showSkinTones={showSkinTones} />
|
|
74
49
|
) : null}
|
|
75
50
|
</EmojiPickerContent>
|
|
76
51
|
</EmojiPickerRoot>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
2
|
import {compact} from "lodash";
|
|
3
3
|
import {Button} from "../button";
|
|
4
|
-
import {AntTabs} from "../antd";
|
|
4
|
+
import {AntTabs} from "../antd/Tabs";
|
|
5
5
|
import {space, textStyles} from "../design-system";
|
|
6
6
|
import {$TSFixMe} from "../tsfixme";
|
|
7
7
|
import {AppIconPicker, AppIconPickerProps} from "./app-icon-picker";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type {Category} from "@fibery/emoji-data";
|
|
2
|
+
|
|
3
|
+
import {css} from "@linaria/core";
|
|
4
|
+
import {space, textStyles, themeVars} from "../../design-system";
|
|
5
|
+
import {useEmojiPickerCtx, useEmojiPickerI18N} from "./root";
|
|
6
|
+
import {IconButton} from "../../button/icon-button";
|
|
7
|
+
import Settings from "../../icons/react/Settings";
|
|
8
|
+
|
|
9
|
+
const categoryLabelCss = css`
|
|
10
|
+
${textStyles.heading6}
|
|
11
|
+
/* in designs it's 31px but we make it equal to emoji size just to make virtualization easier */
|
|
12
|
+
height: var(--fibery-emoji-container-size, 32px);
|
|
13
|
+
color: ${themeVars.accentTextColor};
|
|
14
|
+
background-color: ${themeVars.actionMenuBg};
|
|
15
|
+
padding: ${space.s12}px ${space.s6}px ${space.s4}px ${space.s6}px;
|
|
16
|
+
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: ${space.s4}px;
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
type EmojiPickerCategoryLabelProps = {
|
|
23
|
+
category: Category;
|
|
24
|
+
};
|
|
25
|
+
export const EmojiPickerCategoryLabel: React.FC<EmojiPickerCategoryLabelProps> = ({category}) => {
|
|
26
|
+
const i18n = useEmojiPickerI18N();
|
|
27
|
+
const emojiPickerCtx = useEmojiPickerCtx();
|
|
28
|
+
|
|
29
|
+
const label = i18n.categories[category.id as keyof (typeof i18n)["categories"]] || category.name;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={categoryLabelCss}>
|
|
33
|
+
<span>{label}</span>
|
|
34
|
+
|
|
35
|
+
{category.id === "custom" && emojiPickerCtx.onCustomCategorySettings && (
|
|
36
|
+
<IconButton onClick={emojiPickerCtx.onCustomCategorySettings}>
|
|
37
|
+
<Settings iconSize={16} />
|
|
38
|
+
</IconButton>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -12,6 +12,7 @@ const emojiPickerCss = css`
|
|
|
12
12
|
type EmojiPickerContentSettings = {
|
|
13
13
|
perLine: number;
|
|
14
14
|
emojiSize: number;
|
|
15
|
+
emojiContainerSize: number;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const [Provider, useCtx] = createContext<EmojiPickerContentSettings>("EmojiPickerContentSettings");
|
|
@@ -28,18 +29,29 @@ export const EmojiPickerContent: React.FC<React.PropsWithChildren<EmojiPickerCon
|
|
|
28
29
|
children,
|
|
29
30
|
}) => {
|
|
30
31
|
const width = perLine * (emojiSize + emojiPadding * 2) + contentHorizontalPadding * 2 + measureScrollbar();
|
|
32
|
+
const emojiContainerSize = emojiSize + emojiPadding * 2;
|
|
31
33
|
|
|
32
|
-
const contentSettings = useMemo(
|
|
34
|
+
const contentSettings = useMemo<EmojiPickerContentSettings>(
|
|
33
35
|
() => ({
|
|
36
|
+
emojiContainerSize,
|
|
34
37
|
emojiSize,
|
|
35
38
|
perLine,
|
|
36
39
|
}),
|
|
37
|
-
[emojiSize, perLine]
|
|
40
|
+
[emojiContainerSize, emojiSize, perLine]
|
|
38
41
|
);
|
|
39
42
|
|
|
40
43
|
return (
|
|
41
44
|
<Provider value={contentSettings}>
|
|
42
|
-
<div
|
|
45
|
+
<div
|
|
46
|
+
style={
|
|
47
|
+
{
|
|
48
|
+
"--fibery-emoji-container-size": `${emojiContainerSize}px`,
|
|
49
|
+
"--fibery-emoji-hover-color": emojiHoverColor,
|
|
50
|
+
width,
|
|
51
|
+
} as CSSProperties
|
|
52
|
+
}
|
|
53
|
+
className={emojiPickerCss}
|
|
54
|
+
>
|
|
43
55
|
{children}
|
|
44
56
|
</div>
|
|
45
57
|
</Provider>
|
|
@@ -4,11 +4,13 @@ import {space} from "../../design-system";
|
|
|
4
4
|
const footerCss = css`
|
|
5
5
|
position: relative;
|
|
6
6
|
border-top: 1px solid var(--fibery-color-separatorColor);
|
|
7
|
-
padding: ${space.
|
|
7
|
+
padding: ${space.s6}px ${space.s12}px;
|
|
8
8
|
min-height: 40px;
|
|
9
|
+
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
9
12
|
`;
|
|
10
13
|
|
|
11
14
|
export const EmojiPickerFooter: React.FC<React.PropsWithChildren> = ({children}) => {
|
|
12
|
-
// TODO: Preview + ColorPicker + Skin Tone
|
|
13
15
|
return <div className={footerCss}>{children}</div>;
|
|
14
16
|
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type {EmojiItem} from "@fibery/emoji-data";
|
|
2
|
+
import {css} from "@linaria/core";
|
|
3
|
+
import {memo} from "react";
|
|
4
|
+
import {IconButton} from "../../button/icon-button";
|
|
5
|
+
import {themeVars} from "../../design-system";
|
|
6
|
+
import {useEmojiDataStoreSelector} from "../stores/emoji-data-store";
|
|
7
|
+
import {useEmojiPickerContentSettings} from "./content";
|
|
8
|
+
import {Emoji} from "./emoji";
|
|
9
|
+
import {useSetEmojiPreview} from "./preview-provider";
|
|
10
|
+
import {useEmojiPickerCtx} from "./root";
|
|
11
|
+
import {useEmojiSkin} from "./skin-provider";
|
|
12
|
+
|
|
13
|
+
export type EmojiPickerGridItemProps = {
|
|
14
|
+
id: string;
|
|
15
|
+
categoryId: string;
|
|
16
|
+
highlighted?: boolean;
|
|
17
|
+
/** Custom renderer for emoji items */
|
|
18
|
+
renderEmoji?: (args: {emoji: EmojiItem}) => React.ReactNode;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const EmojiPickerGridItem = memo<EmojiPickerGridItemProps>(({id, categoryId, renderEmoji, highlighted}) => {
|
|
22
|
+
const setEmojiPreview = useSetEmojiPreview();
|
|
23
|
+
const skin = useEmojiSkin();
|
|
24
|
+
const emojiPickerCtx = useEmojiPickerCtx();
|
|
25
|
+
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
26
|
+
|
|
27
|
+
const emoji = useEmojiDataStoreSelector((store) => store.get(id, {skin}));
|
|
28
|
+
|
|
29
|
+
if (!emoji) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// TODO: title should be shown in preview in footer
|
|
34
|
+
const title = emoji.shortNames ? emoji.shortNames[0] : undefined;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<IconButton
|
|
38
|
+
style={{
|
|
39
|
+
width: emojiContentSettings.emojiContainerSize,
|
|
40
|
+
height: emojiContentSettings.emojiContainerSize,
|
|
41
|
+
}}
|
|
42
|
+
size="big"
|
|
43
|
+
onClick={() => emojiPickerCtx.onEmojiSelect(emoji)}
|
|
44
|
+
onMouseEnter={() => setEmojiPreview({emoji, categoryId})}
|
|
45
|
+
onMouseLeave={() => setEmojiPreview(null)}
|
|
46
|
+
data-highlighted={highlighted}
|
|
47
|
+
className={css`
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
&:hover:not(:disabled),
|
|
52
|
+
&:focus-visible,
|
|
53
|
+
&[data-highlighted="true"] {
|
|
54
|
+
background-color: var(--fibery-emoji-hover-color, ${themeVars.badgeBgColor});
|
|
55
|
+
}
|
|
56
|
+
`}
|
|
57
|
+
title={title}
|
|
58
|
+
aria-label={emoji.name}
|
|
59
|
+
>
|
|
60
|
+
{renderEmoji ? (
|
|
61
|
+
renderEmoji({emoji})
|
|
62
|
+
) : (
|
|
63
|
+
<Emoji
|
|
64
|
+
emoji={id}
|
|
65
|
+
size={emojiContentSettings.emojiSize}
|
|
66
|
+
version={emojiPickerCtx.version}
|
|
67
|
+
skin={skin}
|
|
68
|
+
native={emojiPickerCtx.native}
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
</IconButton>
|
|
72
|
+
);
|
|
73
|
+
});
|