@fibery/ui-kit 1.15.0 → 1.16.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 +6 -5
- package/src/antd/styles.ts +4 -4
- package/src/designSystem.ts +6 -17
- package/src/emoji-picker/app-icon-picker.tsx +31 -26
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +107 -0
- package/src/emoji-picker/emoji-picker.tsx +34 -39
- package/src/emoji-picker/icon-emoji-picker.tsx +3 -14
- package/src/emoji-picker/primitives/category.tsx +82 -25
- package/src/emoji-picker/primitives/emoji.tsx +7 -49
- package/src/emoji-picker/primitives/footer.tsx +3 -1
- package/src/emoji-picker/primitives/grid.tsx +53 -23
- package/src/emoji-picker/primitives/search.tsx +21 -11
- package/src/emoji-picker/primitives/skin-tone.tsx +18 -12
- package/src/emoji-picker/stores/emoji-data-store.tsx +0 -1
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +19 -30
- package/src/icons/ast/AiAssistant.ts +1 -1
- package/src/icons/ast/AiAvatar.ts +1 -1
- package/src/icons/ast/AppTemplates.ts +1 -1
- package/src/icons/ast/BellCircle.ts +8 -0
- package/src/icons/ast/BellX.ts +8 -0
- package/src/icons/ast/Bolt.ts +8 -0
- package/src/icons/ast/CheckCircle.ts +8 -0
- package/src/icons/ast/ClockForward.ts +8 -0
- package/src/icons/ast/ColorCodingFilled.ts +8 -0
- package/src/icons/ast/Delete.ts +1 -1
- package/src/icons/ast/EmojiDelete.ts +8 -0
- package/src/icons/ast/ExtensionAssignments.ts +1 -1
- package/src/icons/ast/Fields.ts +1 -1
- package/src/icons/ast/Figma.ts +8 -0
- package/src/icons/ast/GoogleDrive.ts +8 -0
- package/src/icons/ast/GoogleMap.ts +8 -0
- package/src/icons/ast/InvitePeople.ts +1 -1
- package/src/icons/ast/Loom.ts +8 -0
- package/src/icons/ast/Miro.ts +8 -0
- package/src/icons/ast/Mixpanel.ts +8 -0
- package/src/icons/ast/Shared.ts +1 -1
- package/src/icons/ast/Twitter.ts +8 -0
- package/src/icons/ast/Youtube.ts +8 -0
- package/src/icons/ast/index.tsx +15 -0
- package/src/icons/react/BellCircle.tsx +12 -0
- package/src/icons/react/BellX.tsx +12 -0
- package/src/icons/react/Bolt.tsx +12 -0
- package/src/icons/react/CheckCircle.tsx +12 -0
- package/src/icons/react/ClockForward.tsx +12 -0
- package/src/icons/react/ColorCodingFilled.tsx +12 -0
- package/src/icons/react/EmojiDelete.tsx +12 -0
- package/src/icons/react/Figma.tsx +12 -0
- package/src/icons/react/GoogleDrive.tsx +12 -0
- package/src/icons/react/GoogleMap.tsx +12 -0
- package/src/icons/react/Loom.tsx +12 -0
- package/src/icons/react/Miro.tsx +12 -0
- package/src/icons/react/Mixpanel.tsx +12 -0
- package/src/icons/react/Twitter.tsx +12 -0
- package/src/icons/react/Youtube.tsx +12 -0
- package/src/icons/react/index.tsx +15 -0
- package/src/Button/icon-button-with-tooltip.tsx +0 -15
- package/src/emoji-picker/index.tsx +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"files": [
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"license": "UNLICENSED",
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"react-intersection-observer": "9.3.5",
|
|
31
32
|
"@linaria/core": "3.0.0-beta.15",
|
|
32
33
|
"@linaria/react": "3.0.0-beta.15",
|
|
33
34
|
"@popperjs/core": "2.11.6",
|
|
@@ -59,9 +60,9 @@
|
|
|
59
60
|
"react-windowed-select": "5.0.0",
|
|
60
61
|
"screenfull": "6.0.1",
|
|
61
62
|
"ua-parser-js": "0.7.24",
|
|
62
|
-
"@fibery/react": "1.0.3",
|
|
63
63
|
"@fibery/helpers": "1.1.0",
|
|
64
|
-
"@fibery/
|
|
64
|
+
"@fibery/react": "1.0.3",
|
|
65
|
+
"@fibery/emoji-data": "2.1.1"
|
|
65
66
|
},
|
|
66
67
|
"peerDependencies": {
|
|
67
68
|
"react": "^18.2.0",
|
|
@@ -93,8 +94,8 @@
|
|
|
93
94
|
"svgo": "2.8.0",
|
|
94
95
|
"typescript": "5.0.3",
|
|
95
96
|
"unist-util-reduce": "0.2.2",
|
|
96
|
-
"@fibery/
|
|
97
|
-
"@fibery/
|
|
97
|
+
"@fibery/babel-preset": "7.2.0",
|
|
98
|
+
"@fibery/eslint-config": "8.3.0"
|
|
98
99
|
},
|
|
99
100
|
"jest": {
|
|
100
101
|
"testEnvironment": "jsdom",
|
package/src/antd/styles.ts
CHANGED
|
@@ -22,7 +22,7 @@ export const inputOverrides = {
|
|
|
22
22
|
font: "inherit",
|
|
23
23
|
color: themeVars.textColor,
|
|
24
24
|
outline: "none",
|
|
25
|
-
backgroundColor: themeVars.inputBgColor
|
|
25
|
+
backgroundColor: `${themeVars.inputBgColor} !important`,
|
|
26
26
|
borderRadius: border.radius6,
|
|
27
27
|
minHeight: layout.inputHeight,
|
|
28
28
|
paddingTop: 0,
|
|
@@ -32,18 +32,18 @@ export const inputOverrides = {
|
|
|
32
32
|
border: 0,
|
|
33
33
|
borderColor: colors.transparent,
|
|
34
34
|
transition: `box-shadow ${transition}`,
|
|
35
|
-
boxShadow:
|
|
35
|
+
boxShadow: `var(--input-border, ${themeVars.inputBorderColor})`,
|
|
36
36
|
letterSpacing: 0,
|
|
37
37
|
"::placeholder": {
|
|
38
38
|
color: themeVars.inputPlaceholderTextColor,
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
hover: {
|
|
42
|
-
boxShadow:
|
|
42
|
+
boxShadow: `var(--input-hover-border, 0 0 0 1px ${themeVars.opacity.opacity40}) !important`,
|
|
43
43
|
transition: `box-shadow ${transition}`,
|
|
44
44
|
},
|
|
45
45
|
focus: {
|
|
46
|
-
boxShadow:
|
|
46
|
+
boxShadow: `var(--input-focus-border, 0 0 0 1px ${themeVars.opacity.opacity25}), var(--input-focus-shadow, 0 0 0 3px ${themeVars.focus}) !important`,
|
|
47
47
|
transition: `box-shadow ${transition}`,
|
|
48
48
|
},
|
|
49
49
|
disabled: {
|
package/src/designSystem.ts
CHANGED
|
@@ -245,6 +245,8 @@ const lightColors = {
|
|
|
245
245
|
filterGroup1Bg: slate.slate2,
|
|
246
246
|
filterGroup2Bg: slate.slate3,
|
|
247
247
|
filterGroupBorder: blackA.blackA3,
|
|
248
|
+
colorBgNotificationFocusedDefault: indigo.indigo3,
|
|
249
|
+
colorBgNotificationFocusedHover: indigo.indigo4,
|
|
248
250
|
//end
|
|
249
251
|
disabledInversedTextColor: shades.opacity25,
|
|
250
252
|
danger: red.red9,
|
|
@@ -430,6 +432,8 @@ const darkColors = {
|
|
|
430
432
|
filterGroup1Bg: slateDark.slate6,
|
|
431
433
|
filterGroup2Bg: slateDark.slate7,
|
|
432
434
|
filterGroupBorder: whiteA.whiteA3,
|
|
435
|
+
colorBgNotificationFocusedDefault: getOpacities(indigoDark.indigo11).opacity20,
|
|
436
|
+
colorBgNotificationFocusedHover: getOpacities(indigoDark.indigo11).opacity30,
|
|
433
437
|
//end
|
|
434
438
|
disabledInversedTextColor: lights.opacity25,
|
|
435
439
|
danger: redDark.red10,
|
|
@@ -600,24 +604,11 @@ export const getLinkedHighlightBackgroundColor = _.memoize(
|
|
|
600
604
|
(themeMode, color) => `${themeMode}-${color}`
|
|
601
605
|
);
|
|
602
606
|
|
|
603
|
-
// REMOVE AFTER MIGRATION ON BACKEND
|
|
604
|
-
export const migrateEnumColor = (color: string) => {
|
|
605
|
-
const pastelIdx = pastelColors.indexOf(color);
|
|
606
|
-
|
|
607
|
-
if (pastelIdx > -1) {
|
|
608
|
-
return cardTypeColors[pastelIdx];
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
return color;
|
|
612
|
-
};
|
|
613
|
-
|
|
614
607
|
export const getEnumBackgroundColor = _.memoize(
|
|
615
608
|
(mode: ThemeMode, color: string) => {
|
|
616
|
-
const migratedColor = migrateEnumColor(color);
|
|
617
|
-
|
|
618
609
|
return getThemeValue(mode, {
|
|
619
|
-
light: a11yColor(getOpacities(
|
|
620
|
-
dark: a11yColor(getOpacities(
|
|
610
|
+
light: a11yColor(getOpacities(color).opacity20, lightColors.whiteColor, 1),
|
|
611
|
+
dark: a11yColor(getOpacities(color).opacity30, darkColors.menuBg, 1.3),
|
|
621
612
|
});
|
|
622
613
|
},
|
|
623
614
|
(themeMode, color) => `${themeMode}-${color}`
|
|
@@ -660,8 +651,6 @@ export const cardTypeColors = [
|
|
|
660
651
|
"#B04E31",
|
|
661
652
|
] as const;
|
|
662
653
|
|
|
663
|
-
const pastelColors = cardTypeColors.map((color) => makeChromaColor(color).luminance(0.8).hex());
|
|
664
|
-
|
|
665
654
|
export const dropCursorColor = chroma(brandColors.blue).alpha(0.7).css();
|
|
666
655
|
export const colors = {
|
|
667
656
|
...getTypeColors(brandColors.green, "light"),
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {EmojiItem} from "@fibery/emoji-data
|
|
2
|
-
import {
|
|
1
|
+
import {CustomEmoji, EmojiItem} from "@fibery/emoji-data";
|
|
2
|
+
import {useThemeMode} from "../ThemeProvider";
|
|
3
|
+
import {cardTypeColors, getIconColor} from "../designSystem";
|
|
3
4
|
import {$TSFixMe} from "../tsfixme";
|
|
4
|
-
import {
|
|
5
|
+
import {EmojiPickerContentWithColor} from "./emoji-picker-content-with-color";
|
|
5
6
|
import {EmojiPickerContent} from "./primitives/content";
|
|
6
|
-
import {EmojiPickerFooter} from "./primitives/footer";
|
|
7
|
-
import {EmojiPickerGrid} from "./primitives/grid";
|
|
8
|
-
import {EmojiPickerHeader} from "./primitives/header";
|
|
9
7
|
import {EmojiPickerRoot} from "./primitives/root";
|
|
10
|
-
import {
|
|
11
|
-
import {cardTypeColors} from "../designSystem";
|
|
8
|
+
import {LazyIconDataStore} from "./stores/lazy-icon-data-store";
|
|
12
9
|
|
|
13
10
|
const i18n = {search: "Search icon...", notfound: "No Icons Found"};
|
|
14
11
|
|
|
@@ -19,35 +16,43 @@ export type AppIconPickerProps = {
|
|
|
19
16
|
onColorSelect?: (c: $TSFixMe) => void;
|
|
20
17
|
|
|
21
18
|
onSelect: (emoji: EmojiItem) => void;
|
|
19
|
+
autoFocus?: boolean;
|
|
22
20
|
};
|
|
23
21
|
export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
24
22
|
onSelect,
|
|
25
23
|
color,
|
|
26
|
-
colors = cardTypeColors,
|
|
24
|
+
colors = cardTypeColors as unknown as string[],
|
|
27
25
|
onColorSelect,
|
|
28
26
|
getHoverColor,
|
|
27
|
+
autoFocus = true,
|
|
29
28
|
}) => {
|
|
29
|
+
const themeMode = useThemeMode();
|
|
30
|
+
|
|
30
31
|
return (
|
|
31
32
|
<EmojiPickerRoot i18n={i18n} onEmojiSelect={onSelect}>
|
|
32
33
|
<EmojiPickerContent emojiHoverColor={color ? getHoverColor?.(color) : undefined} emojiSize={20}>
|
|
33
|
-
<LazyIconDataStore fallback={<div style={{height: "
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
<LazyIconDataStore fallback={<div style={{height: "302px"}}></div>}>
|
|
35
|
+
<EmojiPickerContentWithColor
|
|
36
|
+
color={color}
|
|
37
|
+
colors={colors}
|
|
38
|
+
getHoverColor={getHoverColor}
|
|
39
|
+
onColorSelect={onColorSelect}
|
|
40
|
+
searchAutofocus={autoFocus}
|
|
41
|
+
renderEmoji={({emoji}) => (
|
|
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
|
+
)}
|
|
54
|
+
/>
|
|
39
55
|
</LazyIconDataStore>
|
|
40
|
-
|
|
41
|
-
{onColorSelect ? (
|
|
42
|
-
<EmojiPickerFooter>
|
|
43
|
-
<ColorPicker
|
|
44
|
-
colors={colors}
|
|
45
|
-
getSwatchHoverColor={getHoverColor}
|
|
46
|
-
color={color}
|
|
47
|
-
onChangeComplete={onColorSelect}
|
|
48
|
-
/>
|
|
49
|
-
</EmojiPickerFooter>
|
|
50
|
-
) : null}
|
|
51
56
|
</EmojiPickerContent>
|
|
52
57
|
</EmojiPickerRoot>
|
|
53
58
|
);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {css} from "@linaria/core";
|
|
2
|
+
import {useState} from "react";
|
|
3
|
+
import {IconButton} from "../Button/icon-button";
|
|
4
|
+
import {CollapsibleContent, CollapsibleRoot, CollapsibleTrigger} from "../Collapsible";
|
|
5
|
+
import {ColorPicker} from "../ColorPicker";
|
|
6
|
+
import {useThemeMode} from "../ThemeProvider";
|
|
7
|
+
import {getIconColor, space} from "../designSystem";
|
|
8
|
+
import ColorCoding from "../icons/react/ColorCoding";
|
|
9
|
+
import ColorCodingFilled from "../icons/react/ColorCodingFilled";
|
|
10
|
+
import {$TSFixMe} from "../tsfixme";
|
|
11
|
+
import {EmojiPickerGrid, EmojiPickerGridProps} from "./primitives/grid";
|
|
12
|
+
import {EmojiPickerHeader} from "./primitives/header";
|
|
13
|
+
import {EmojiPickerSearch} from "./primitives/search";
|
|
14
|
+
|
|
15
|
+
const colorPickerWrapperCss = css`
|
|
16
|
+
padding-top: ${space.l}px;
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const disableScrollCss = css`
|
|
20
|
+
overflow-y: hidden;
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
type ColorPickerCollapsibleTrigger = {opened: boolean; color?: string};
|
|
24
|
+
|
|
25
|
+
const ColorPickerCollapsibleTrigger: React.FC<ColorPickerCollapsibleTrigger> = ({opened, color}) => {
|
|
26
|
+
const themeMode = useThemeMode();
|
|
27
|
+
const iconColor = color ? getIconColor(themeMode, color) : undefined;
|
|
28
|
+
|
|
29
|
+
const Icon = opened ? ColorCodingFilled : ColorCoding;
|
|
30
|
+
|
|
31
|
+
const label = opened ? "Close color picker" : "Open color picker";
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<CollapsibleTrigger asChild>
|
|
35
|
+
<IconButton
|
|
36
|
+
aria-label={label}
|
|
37
|
+
size="big"
|
|
38
|
+
className={css`
|
|
39
|
+
border-top-left-radius: 0;
|
|
40
|
+
border-bottom-left-radius: 0;
|
|
41
|
+
`}
|
|
42
|
+
>
|
|
43
|
+
<Icon color={iconColor} iconSize={18} containerSize={20} />
|
|
44
|
+
</IconButton>
|
|
45
|
+
</CollapsibleTrigger>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const collapsibleWrapperCss = css`
|
|
50
|
+
max-height: 302px; // search + emoji grid
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
export type EmojiPickerContentWithColorProps = {
|
|
55
|
+
color?: string;
|
|
56
|
+
getHoverColor?: (color: string) => string | undefined;
|
|
57
|
+
colors?: string[];
|
|
58
|
+
onColorSelect?: (c: $TSFixMe) => void;
|
|
59
|
+
|
|
60
|
+
searchRef?: React.RefObject<HTMLInputElement>;
|
|
61
|
+
searchAutofocus?: boolean;
|
|
62
|
+
} & Pick<EmojiPickerGridProps, "renderEmoji">;
|
|
63
|
+
|
|
64
|
+
export const EmojiPickerContentWithColor: React.FC<EmojiPickerContentWithColorProps> = ({
|
|
65
|
+
searchRef,
|
|
66
|
+
colors,
|
|
67
|
+
color,
|
|
68
|
+
onColorSelect,
|
|
69
|
+
getHoverColor,
|
|
70
|
+
searchAutofocus = true,
|
|
71
|
+
renderEmoji,
|
|
72
|
+
}) => {
|
|
73
|
+
const [colorOpened, setColorOpened] = useState(false);
|
|
74
|
+
|
|
75
|
+
const showColorPicker = Boolean(onColorSelect);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<CollapsibleRoot
|
|
79
|
+
className={collapsibleWrapperCss}
|
|
80
|
+
open={colorOpened}
|
|
81
|
+
onOpenChange={setColorOpened}
|
|
82
|
+
onWheel={() => setColorOpened(false)}
|
|
83
|
+
>
|
|
84
|
+
<EmojiPickerHeader>
|
|
85
|
+
<EmojiPickerSearch
|
|
86
|
+
searchRef={searchRef}
|
|
87
|
+
autoFocus={searchAutofocus}
|
|
88
|
+
extraAction={showColorPicker ? <ColorPickerCollapsibleTrigger opened={colorOpened} color={color} /> : null}
|
|
89
|
+
/>
|
|
90
|
+
{showColorPicker ? (
|
|
91
|
+
<CollapsibleContent>
|
|
92
|
+
<div className={colorPickerWrapperCss}>
|
|
93
|
+
<ColorPicker
|
|
94
|
+
colors={colors}
|
|
95
|
+
getSwatchHoverColor={getHoverColor}
|
|
96
|
+
color={color}
|
|
97
|
+
onChangeComplete={onColorSelect}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
</CollapsibleContent>
|
|
101
|
+
) : null}
|
|
102
|
+
</EmojiPickerHeader>
|
|
103
|
+
|
|
104
|
+
<EmojiPickerGrid className={colorOpened ? disableScrollCss : undefined} renderEmoji={renderEmoji} />
|
|
105
|
+
</CollapsibleRoot>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import {EmojiItem} from "@fibery/emoji-data/lib/src";
|
|
2
|
+
import {css} from "@linaria/core";
|
|
3
|
+
import {Button} from "../Button";
|
|
4
|
+
import {cardTypeColors, space} from "../designSystem";
|
|
2
5
|
import {$TSFixMe} from "../tsfixme";
|
|
3
|
-
import {
|
|
6
|
+
import {EmojiPickerContentWithColor} from "./emoji-picker-content-with-color";
|
|
4
7
|
import {EmojiPickerContent} from "./primitives/content";
|
|
5
|
-
import {EmojiPickerHeader} from "./primitives/header";
|
|
6
|
-
import {EmojiPickerSearch} from "./primitives/search";
|
|
7
|
-
import {cx, css} from "@linaria/core";
|
|
8
|
-
import {EmojiPickerSkinTone} from "./primitives/skin-tone";
|
|
9
|
-
import {EmojiPickerGrid} from "./primitives/grid";
|
|
10
|
-
import {ColorPicker} from "../ColorPicker";
|
|
11
8
|
import {EmojiPickerFooter} from "./primitives/footer";
|
|
12
|
-
import {
|
|
9
|
+
import {EmojiPickerRoot} from "./primitives/root";
|
|
10
|
+
import {EmojiPickerSkinTone} from "./primitives/skin-tone";
|
|
13
11
|
|
|
14
12
|
const i18n = {search: "Search emoji..."};
|
|
15
13
|
|
|
@@ -19,6 +17,7 @@ export type EmojiPickerProps = {
|
|
|
19
17
|
colors?: string[];
|
|
20
18
|
onColorSelect?: (c: $TSFixMe) => void;
|
|
21
19
|
onCustomCategorySettings?: () => void;
|
|
20
|
+
onAddCustomEmoji?: () => void;
|
|
22
21
|
onSelect: (emoji: EmojiItem) => void;
|
|
23
22
|
showSkinTones?: boolean;
|
|
24
23
|
|
|
@@ -27,48 +26,44 @@ export type EmojiPickerProps = {
|
|
|
27
26
|
export const EmojiPicker: React.FC<EmojiPickerProps> = ({
|
|
28
27
|
onSelect,
|
|
29
28
|
color,
|
|
30
|
-
colors = cardTypeColors,
|
|
29
|
+
colors = cardTypeColors as unknown as string[],
|
|
31
30
|
onColorSelect,
|
|
32
31
|
onCustomCategorySettings,
|
|
32
|
+
onAddCustomEmoji,
|
|
33
33
|
getHoverColor,
|
|
34
34
|
showSkinTones,
|
|
35
35
|
searchRef,
|
|
36
36
|
}) => {
|
|
37
|
+
const showFooter = Boolean(onAddCustomEmoji) || showSkinTones;
|
|
38
|
+
|
|
37
39
|
return (
|
|
38
40
|
<EmojiPickerRoot i18n={i18n} onEmojiSelect={onSelect} onCustomCategorySettings={onCustomCategorySettings}>
|
|
39
41
|
<EmojiPickerContent emojiHoverColor={color ? getHoverColor?.(color) : undefined} emojiSize={20}>
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
width: 250px !important;
|
|
48
|
-
`
|
|
49
|
-
)}
|
|
50
|
-
/>
|
|
51
|
-
{/* Temporary hacks. SkinTone should move to footer */}
|
|
52
|
-
{showSkinTones ? (
|
|
53
|
-
<EmojiPickerSkinTone
|
|
54
|
-
className={css`
|
|
55
|
-
position: absolute;
|
|
56
|
-
top: 4px;
|
|
57
|
-
right: 12px;
|
|
58
|
-
`}
|
|
59
|
-
/>
|
|
60
|
-
) : null}
|
|
61
|
-
</EmojiPickerHeader>
|
|
62
|
-
<EmojiPickerGrid />
|
|
42
|
+
<EmojiPickerContentWithColor
|
|
43
|
+
color={color}
|
|
44
|
+
colors={colors}
|
|
45
|
+
getHoverColor={getHoverColor}
|
|
46
|
+
onColorSelect={onColorSelect}
|
|
47
|
+
searchRef={searchRef}
|
|
48
|
+
/>
|
|
63
49
|
|
|
64
|
-
{
|
|
50
|
+
{showFooter ? (
|
|
65
51
|
<EmojiPickerFooter>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
{onAddCustomEmoji ? (
|
|
53
|
+
<Button size=":button-size/small" onClick={onAddCustomEmoji}>
|
|
54
|
+
Add Emoji
|
|
55
|
+
</Button>
|
|
56
|
+
) : null}
|
|
57
|
+
|
|
58
|
+
{showSkinTones ? (
|
|
59
|
+
<EmojiPickerSkinTone
|
|
60
|
+
className={css`
|
|
61
|
+
position: absolute;
|
|
62
|
+
top: 4px;
|
|
63
|
+
right: ${space.l}px;
|
|
64
|
+
`}
|
|
65
|
+
/>
|
|
66
|
+
) : null}
|
|
72
67
|
</EmojiPickerFooter>
|
|
73
68
|
) : null}
|
|
74
69
|
</EmojiPickerContent>
|
|
@@ -6,6 +6,7 @@ import {space, textStyles} from "../designSystem";
|
|
|
6
6
|
import {$TSFixMe} from "../tsfixme";
|
|
7
7
|
import {AppIconPicker, AppIconPickerProps} from "./app-icon-picker";
|
|
8
8
|
import {EmojiPicker, EmojiPickerProps} from "./emoji-picker";
|
|
9
|
+
import EmojiDelete from "../icons/react/EmojiDelete";
|
|
9
10
|
|
|
10
11
|
const TabHeader: React.FC<React.PropsWithChildren> = ({children}) => (
|
|
11
12
|
<div
|
|
@@ -27,7 +28,6 @@ export type IconEmojiPickerProps = React.PropsWithChildren<{
|
|
|
27
28
|
onCustomEmojisSettings?: () => void;
|
|
28
29
|
onReset?: () => void;
|
|
29
30
|
resetLabel?: string;
|
|
30
|
-
createLabel?: string;
|
|
31
31
|
defaultTab?: TabKey;
|
|
32
32
|
showColorPickerOnTabs?: TabKey[];
|
|
33
33
|
color?: string;
|
|
@@ -41,7 +41,6 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
41
41
|
onCustomEmojisSettings,
|
|
42
42
|
defaultTab,
|
|
43
43
|
onReset,
|
|
44
|
-
createLabel = "Add Emoji",
|
|
45
44
|
resetLabel = "Reset",
|
|
46
45
|
showColorPickerOnTabs = ["icons", "emojis"],
|
|
47
46
|
color,
|
|
@@ -62,21 +61,11 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
62
61
|
color={color}
|
|
63
62
|
onColorSelect={showColorPickerOnTabs.includes("emojis") ? onColorSelect : undefined}
|
|
64
63
|
onCustomCategorySettings={onCustomEmojisSettings}
|
|
64
|
+
onAddCustomEmoji={onCreateClick}
|
|
65
65
|
getHoverColor={getHoverColor}
|
|
66
66
|
onSelect={onEmojiSelect}
|
|
67
67
|
showSkinTones
|
|
68
68
|
/>
|
|
69
|
-
{onCreateClick && (
|
|
70
|
-
<div
|
|
71
|
-
className={css`
|
|
72
|
-
padding: ${space.l}px;
|
|
73
|
-
`}
|
|
74
|
-
>
|
|
75
|
-
<Button size=":button-size/small" onClick={onCreateClick}>
|
|
76
|
-
{createLabel}
|
|
77
|
-
</Button>
|
|
78
|
-
</div>
|
|
79
|
-
)}
|
|
80
69
|
</>
|
|
81
70
|
),
|
|
82
71
|
},
|
|
@@ -100,7 +89,7 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
100
89
|
padding-right: ${space.l}px;
|
|
101
90
|
`}
|
|
102
91
|
>
|
|
103
|
-
<Button size={":button-size/small"} onClick={onReset}>
|
|
92
|
+
<Button Icon={EmojiDelete} size={":button-size/small"} onClick={onReset}>
|
|
104
93
|
{resetLabel}
|
|
105
94
|
</Button>
|
|
106
95
|
</div>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {Category} from "@fibery/emoji-data";
|
|
2
|
-
import {
|
|
1
|
+
import {Category, EmojiItem} from "@fibery/emoji-data";
|
|
2
|
+
import {css} from "@linaria/core";
|
|
3
3
|
import {memo} from "react";
|
|
4
|
+
import {useInView} from "react-intersection-observer";
|
|
4
5
|
import {IconButton} from "../../Button/icon-button";
|
|
5
6
|
import {space, textStyles, themeVars} from "../../designSystem";
|
|
6
7
|
import {Settings} from "../../icons/react";
|
|
8
|
+
import {useEmojiDataStoreSelector} from "../stores/emoji-data-store";
|
|
7
9
|
import {useEmojiPickerContentSettings} from "./content";
|
|
8
10
|
import {Emoji} from "./emoji";
|
|
9
11
|
import {emojiPadding} from "./layout";
|
|
@@ -24,7 +26,6 @@ const categoryLabelCss = css`
|
|
|
24
26
|
align-items: center;
|
|
25
27
|
gap: ${space.xs}px;
|
|
26
28
|
|
|
27
|
-
/* is required only because contentVisibility lifts emoji up */
|
|
28
29
|
z-index: 1;
|
|
29
30
|
`;
|
|
30
31
|
|
|
@@ -62,22 +63,89 @@ const NotFound = () => {
|
|
|
62
63
|
);
|
|
63
64
|
};
|
|
64
65
|
|
|
65
|
-
type
|
|
66
|
-
|
|
66
|
+
type CategoryItemProps = {
|
|
67
|
+
id: string;
|
|
68
|
+
/** Custom renderer for emoji items */
|
|
69
|
+
renderEmoji?: (args: {emoji: EmojiItem}) => React.ReactNode;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const CategoryItem: React.FC<CategoryItemProps> = ({id, renderEmoji}) => {
|
|
73
|
+
const skin = useEmojiSkin();
|
|
74
|
+
const emojiPickerCtx = useEmojiPickerCtx();
|
|
75
|
+
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
76
|
+
|
|
77
|
+
const emoji = useEmojiDataStoreSelector((store) => store.get(id));
|
|
78
|
+
|
|
79
|
+
if (!emoji) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// TODO: title should be shown in preview in footer
|
|
84
|
+
const title = emoji.shortNames ? emoji.shortNames[0] : undefined;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<IconButton
|
|
88
|
+
size="big"
|
|
89
|
+
onClick={() => emojiPickerCtx.onEmojiSelect(emoji)}
|
|
90
|
+
className={css`
|
|
91
|
+
&:hover:not(:disabled),
|
|
92
|
+
&:focus-visible {
|
|
93
|
+
background-color: var(--fibery-emoji-hover-color, ${themeVars.badgeBgColor});
|
|
94
|
+
}
|
|
95
|
+
`}
|
|
96
|
+
title={title}
|
|
97
|
+
aria-label={emoji.name}
|
|
98
|
+
>
|
|
99
|
+
{renderEmoji ? (
|
|
100
|
+
renderEmoji({emoji})
|
|
101
|
+
) : (
|
|
102
|
+
<Emoji
|
|
103
|
+
emoji={id}
|
|
104
|
+
size={emojiContentSettings.emojiSize}
|
|
105
|
+
version={emojiPickerCtx.version}
|
|
106
|
+
skin={skin}
|
|
107
|
+
native={emojiPickerCtx.native}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
</IconButton>
|
|
111
|
+
);
|
|
67
112
|
};
|
|
68
|
-
|
|
113
|
+
|
|
114
|
+
export type EmojiPickerCategoryProps = {
|
|
115
|
+
category: Category;
|
|
116
|
+
|
|
117
|
+
preRender?: boolean;
|
|
118
|
+
scrollParent: Element | null;
|
|
119
|
+
} & Pick<CategoryItemProps, "renderEmoji">;
|
|
120
|
+
|
|
121
|
+
export const EmojiPickerCategory = memo<EmojiPickerCategoryProps>(function EmojiPickerCategoryComponent({
|
|
122
|
+
category,
|
|
123
|
+
renderEmoji,
|
|
124
|
+
scrollParent,
|
|
125
|
+
preRender = false,
|
|
126
|
+
}) {
|
|
69
127
|
const i18n = useEmojiPickerI18N();
|
|
70
128
|
const emojiPickerCtx = useEmojiPickerCtx();
|
|
71
129
|
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
72
130
|
|
|
131
|
+
const {ref, inView} = useInView({
|
|
132
|
+
root: scrollParent,
|
|
133
|
+
rootMargin: `129px 0px`, // grid height / 2
|
|
134
|
+
initialInView: preRender,
|
|
135
|
+
fallbackInView: true,
|
|
136
|
+
triggerOnce: true,
|
|
137
|
+
});
|
|
138
|
+
|
|
73
139
|
const label = i18n.categories[category.id as keyof (typeof i18n)["categories"]] || category.name;
|
|
74
140
|
|
|
75
|
-
const
|
|
141
|
+
const emojiSize = emojiContentSettings.emojiSize + emojiPadding * 2;
|
|
76
142
|
|
|
77
143
|
return (
|
|
78
144
|
<section className={categoryCss} aria-label={label}>
|
|
79
145
|
<div className={categoryLabelCss}>
|
|
80
|
-
|
|
146
|
+
{/* already labeled by the section aria-label */}
|
|
147
|
+
<span aria-hidden={true}>{label}</span>
|
|
148
|
+
|
|
81
149
|
{category.id === "custom" && emojiPickerCtx.onCustomCategorySettings && (
|
|
82
150
|
<IconButton onClick={emojiPickerCtx.onCustomCategorySettings}>
|
|
83
151
|
<Settings iconSize={16} />
|
|
@@ -86,28 +154,17 @@ export const EmojiPickerCategory = memo<EmojiPickerCategoryProps>(function Emoji
|
|
|
86
154
|
</div>
|
|
87
155
|
|
|
88
156
|
{category.emojis.length > 0 ? (
|
|
89
|
-
<ul className={categoryListCss}>
|
|
157
|
+
<ul ref={ref} className={categoryListCss}>
|
|
90
158
|
{category.emojis.map((id) => {
|
|
91
159
|
return (
|
|
92
160
|
<li
|
|
93
|
-
style={
|
|
94
|
-
// css-only virtualization until implementing the real one
|
|
95
|
-
{
|
|
96
|
-
contentVisibility: "auto",
|
|
97
|
-
containIntrinsicSize: `${emojiContentSettings.emojiSize + emojiPadding * 2}px`,
|
|
98
|
-
} as CSSProperties
|
|
99
|
-
}
|
|
100
161
|
key={id}
|
|
162
|
+
style={{
|
|
163
|
+
width: emojiSize,
|
|
164
|
+
height: emojiSize,
|
|
165
|
+
}}
|
|
101
166
|
>
|
|
102
|
-
<
|
|
103
|
-
onClick={emojiPickerCtx.onEmojiSelect}
|
|
104
|
-
emoji={id}
|
|
105
|
-
size={emojiContentSettings.emojiSize}
|
|
106
|
-
version={emojiPickerCtx.version}
|
|
107
|
-
skin={skin}
|
|
108
|
-
tooltip
|
|
109
|
-
native={emojiPickerCtx.native}
|
|
110
|
-
/>
|
|
167
|
+
{inView ? <CategoryItem id={id} renderEmoji={renderEmoji} /> : null}
|
|
111
168
|
</li>
|
|
112
169
|
);
|
|
113
170
|
})}
|