@fibery/ui-kit 1.13.0 → 1.15.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 +7 -9
- package/src/antd/styles.ts +20 -3
- package/src/designSystem.ts +14 -11
- package/src/emoji-picker/app-icon-picker.tsx +54 -0
- package/src/emoji-picker/emoji-index.ts +8 -0
- package/src/emoji-picker/emoji-picker.tsx +77 -0
- package/src/emoji-picker/emoji.tsx +8 -0
- package/src/{emoji-mart → emoji-picker}/icon-emoji-picker.tsx +39 -17
- package/src/emoji-picker/index.tsx +5 -0
- package/src/emoji-picker/primitives/category.tsx +120 -0
- package/src/emoji-picker/primitives/content.tsx +48 -0
- package/src/emoji-picker/primitives/emoji.tsx +131 -0
- package/src/emoji-picker/primitives/footer.tsx +12 -0
- package/src/emoji-picker/primitives/grid.tsx +67 -0
- package/src/emoji-picker/primitives/header.tsx +11 -0
- package/src/emoji-picker/primitives/layout.ts +5 -0
- package/src/emoji-picker/primitives/root.tsx +89 -0
- package/src/emoji-picker/primitives/search-provider.tsx +22 -0
- package/src/emoji-picker/primitives/search.tsx +141 -0
- package/src/emoji-picker/primitives/skin-provider.tsx +27 -0
- package/src/emoji-picker/primitives/skin-tone.tsx +103 -0
- package/src/emoji-picker/stores/emoji-data-store.tsx +50 -0
- package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +29 -0
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +55 -0
- package/src/emoji-picker/stores/static-emoji-data-store.tsx +16 -0
- package/src/emoji-picker/utils/emoji-set.ts +5 -0
- package/src/{emoji-mart → emoji-picker/utils}/emoji-support.ts +6 -10
- package/src/emoji-picker/utils/frequently.ts +82 -0
- package/src/emoji-picker/utils/load-emoji-data.ts +4 -0
- package/src/emoji-picker/utils/store.ts +40 -0
- package/src/icons/ast/AddAfter.ts +8 -0
- package/src/icons/ast/AddBefore.ts +8 -0
- package/src/icons/ast/ArrowBarLeft.ts +8 -0
- package/src/icons/ast/ArrowBarRight.ts +8 -0
- package/src/icons/ast/Columns2.ts +8 -0
- package/src/icons/ast/Columns4.ts +8 -0
- package/src/icons/ast/LineDivider.ts +8 -0
- package/src/icons/ast/index.tsx +7 -0
- package/src/icons/react/AddAfter.tsx +12 -0
- package/src/icons/react/AddBefore.tsx +12 -0
- package/src/icons/react/ArrowBarLeft.tsx +12 -0
- package/src/icons/react/ArrowBarRight.tsx +12 -0
- package/src/icons/react/Columns2.tsx +12 -0
- package/src/icons/react/Columns4.tsx +12 -0
- package/src/icons/react/LineDivider.tsx +12 -0
- package/src/icons/react/index.tsx +7 -0
- package/src/emoji-mart/app-icon-picker.tsx +0 -68
- package/src/emoji-mart/data/get-data.tsx +0 -58
- package/src/emoji-mart/emoji/emoji.tsx +0 -26
- package/src/emoji-mart/emoji/index.tsx +0 -24
- package/src/emoji-mart/emoji-index.ts +0 -5
- package/src/emoji-mart/emoji-mart.tsx +0 -216
- package/src/emoji-mart/emoji-picker.tsx +0 -78
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"files": [
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"src/tooltip.tsx",
|
|
24
24
|
"src/BackButton.tsx",
|
|
25
25
|
"src/Button",
|
|
26
|
-
"src/emoji-
|
|
26
|
+
"src/emoji-picker/**/*.ts*",
|
|
27
27
|
"src/a11y-color.ts"
|
|
28
28
|
],
|
|
29
29
|
"license": "UNLICENSED",
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"color-hash": "1.0.3",
|
|
44
44
|
"d3-shape": "1.3.7",
|
|
45
45
|
"date-fns": "^2.29.2",
|
|
46
|
-
"emoji-mart": "3.0.1",
|
|
47
46
|
"invariant": "2.2.4",
|
|
48
47
|
"lodash": "4.17.21",
|
|
49
48
|
"md5": "2.2.1",
|
|
@@ -60,9 +59,9 @@
|
|
|
60
59
|
"react-windowed-select": "5.0.0",
|
|
61
60
|
"screenfull": "6.0.1",
|
|
62
61
|
"ua-parser-js": "0.7.24",
|
|
63
|
-
"@fibery/
|
|
64
|
-
"@fibery/helpers": "1.0
|
|
65
|
-
"@fibery/
|
|
62
|
+
"@fibery/react": "1.0.3",
|
|
63
|
+
"@fibery/helpers": "1.1.0",
|
|
64
|
+
"@fibery/emoji-data": "2.1.0"
|
|
66
65
|
},
|
|
67
66
|
"peerDependencies": {
|
|
68
67
|
"react": "^18.2.0",
|
|
@@ -78,7 +77,6 @@
|
|
|
78
77
|
"@testing-library/user-event": "13.5.0",
|
|
79
78
|
"@types/chroma-js": "2.1.3",
|
|
80
79
|
"@types/color-hash": "1.0.2",
|
|
81
|
-
"@types/emoji-mart": "3.0.8",
|
|
82
80
|
"@types/invariant": "2.2.34",
|
|
83
81
|
"@types/lodash": "4.14.172",
|
|
84
82
|
"@types/prop-types": "15.7.5",
|
|
@@ -95,8 +93,8 @@
|
|
|
95
93
|
"svgo": "2.8.0",
|
|
96
94
|
"typescript": "5.0.3",
|
|
97
95
|
"unist-util-reduce": "0.2.2",
|
|
98
|
-
"@fibery/
|
|
99
|
-
"@fibery/
|
|
96
|
+
"@fibery/eslint-config": "8.3.0",
|
|
97
|
+
"@fibery/babel-preset": "7.2.0"
|
|
100
98
|
},
|
|
101
99
|
"jest": {
|
|
102
100
|
"testEnvironment": "jsdom",
|
package/src/antd/styles.ts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
2
|
import {colors, layout, border, shadows, space, textStyles, themeVars, transition} from "../designSystem";
|
|
3
3
|
|
|
4
|
+
const inputVariables = {
|
|
5
|
+
default: {
|
|
6
|
+
"--input-border": themeVars.inputBorderColor,
|
|
7
|
+
"--input-hover-border": `0 0 0 1px ${themeVars.opacity.opacity40}`,
|
|
8
|
+
"--input-focus-border": `0 0 0 1px ${themeVars.opacity.opacity25}`,
|
|
9
|
+
"--input-focus-shadow": `0 0 0 3px ${themeVars.focus}`,
|
|
10
|
+
},
|
|
11
|
+
error: {
|
|
12
|
+
"--input-border": themeVars.inputErrorBorderColor,
|
|
13
|
+
"--input-hover-border": themeVars.inputErrorBorderHoverColor,
|
|
14
|
+
"--input-focus-border": themeVars.inputErrorBorderFocusColor,
|
|
15
|
+
"--input-focus-shadow": themeVars.inputErrorBorderFocusShadow,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
4
19
|
export const inputOverrides = {
|
|
5
20
|
main: {
|
|
21
|
+
...inputVariables.default,
|
|
6
22
|
font: "inherit",
|
|
7
23
|
color: themeVars.textColor,
|
|
8
24
|
outline: "none",
|
|
@@ -16,18 +32,18 @@ export const inputOverrides = {
|
|
|
16
32
|
border: 0,
|
|
17
33
|
borderColor: colors.transparent,
|
|
18
34
|
transition: `box-shadow ${transition}`,
|
|
19
|
-
boxShadow:
|
|
35
|
+
boxShadow: "var(--input-border)",
|
|
20
36
|
letterSpacing: 0,
|
|
21
37
|
"::placeholder": {
|
|
22
38
|
color: themeVars.inputPlaceholderTextColor,
|
|
23
39
|
},
|
|
24
40
|
},
|
|
25
41
|
hover: {
|
|
26
|
-
boxShadow:
|
|
42
|
+
boxShadow: "var(--input-hover-border) !important",
|
|
27
43
|
transition: `box-shadow ${transition}`,
|
|
28
44
|
},
|
|
29
45
|
focus: {
|
|
30
|
-
boxShadow:
|
|
46
|
+
boxShadow: "var(--input-focus-border), var(--input-focus-shadow) !important",
|
|
31
47
|
transition: `box-shadow ${transition}`,
|
|
32
48
|
},
|
|
33
49
|
disabled: {
|
|
@@ -63,6 +79,7 @@ export const inputStyles = css`
|
|
|
63
79
|
},
|
|
64
80
|
"& .ant-input-group": {borderSpacing: 1, ...textStyles.regular},
|
|
65
81
|
"& .ant-input": inputOverrides.main,
|
|
82
|
+
"& .ant-input-status-error": inputVariables.error,
|
|
66
83
|
"& .ant-input[readonly].ant-input[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
|
67
84
|
"& .ant-input:hover[readonly].ant-input:hover[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
|
68
85
|
"& .ant-input-affix-wrapper:hover .ant-input[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
package/src/designSystem.ts
CHANGED
|
@@ -157,6 +157,10 @@ const lightColors = {
|
|
|
157
157
|
inputBorderFocusColor: `0 0 0 1px ${getOpacities(slate.slate8).opacity100}`,
|
|
158
158
|
inputBorderBlendMode: "multiply",
|
|
159
159
|
inputPlaceholderTextColor: slate.slate9,
|
|
160
|
+
inputErrorBorderColor: `0 0 0 1px ${red.red11}`,
|
|
161
|
+
inputErrorBorderHoverColor: `0 0 0 1px ${getOpacities(red.red11).opacity40}`,
|
|
162
|
+
inputErrorBorderFocusColor: `0 0 0 1px ${getOpacities(red.red11).opacity25}`,
|
|
163
|
+
inputErrorBorderFocusShadow: `0 0 0 3px ${getOpacities(red.red11).opacity25}`,
|
|
160
164
|
buttonPrimaryColor: indigo.indigo10,
|
|
161
165
|
buttonColor: slate.slate10,
|
|
162
166
|
buttonPrimaryTextColor: slate.slate2,
|
|
@@ -269,11 +273,12 @@ const lightColors = {
|
|
|
269
273
|
gridHeaderTextColor: slate.slate9,
|
|
270
274
|
// cell
|
|
271
275
|
gridCellBgColor: whiteA.whiteA0,
|
|
272
|
-
gridCellBorderColor: slate.
|
|
276
|
+
gridCellBorderColor: slate.slate5,
|
|
273
277
|
gridPinnedCellBorderColor: slate.slate8,
|
|
274
278
|
gridDisabledCellBgColor: slate.slate2,
|
|
275
279
|
gridSelectedCellBgColor: indigo.indigo3,
|
|
276
|
-
|
|
280
|
+
gridHighlightedCellBgColor: indigo.indigo4,
|
|
281
|
+
gridSelectedCellBorderColor: indigo.indigo6,
|
|
277
282
|
gridSelectedPinnedCellBorderColor: indigo.indigo7,
|
|
278
283
|
gridDisabledSelectedCellBgColor: indigo.indigo4,
|
|
279
284
|
gridActiveCellBorderColor: indigo.indigo8,
|
|
@@ -340,6 +345,10 @@ const darkColors = {
|
|
|
340
345
|
inputBorderFocusColor: `0 0 0 1px ${getOpacities(slateDark.slate9).opacity100}`,
|
|
341
346
|
inputBorderBlendMode: "lighten",
|
|
342
347
|
inputPlaceholderTextColor: slateDark.slate9,
|
|
348
|
+
inputErrorBorderColor: `0 0 0 1px ${red.red7}`,
|
|
349
|
+
inputErrorBorderHoverColor: `0 0 0 1px ${getOpacities(red.red7).opacity40}`,
|
|
350
|
+
inputErrorBorderFocusColor: `0 0 0 1px ${getOpacities(red.red7).opacity25}`,
|
|
351
|
+
inputErrorBorderFocusShadow: `0 0 0 3px ${getOpacities(red.red7).opacity25}`,
|
|
343
352
|
buttonPrimaryColor: indigoDark.indigo10,
|
|
344
353
|
buttonColor: slateDark.slate10,
|
|
345
354
|
buttonPrimaryTextColor: slate.slate6,
|
|
@@ -449,11 +458,12 @@ const darkColors = {
|
|
|
449
458
|
gridHeaderTextColor: slateDark.slate10,
|
|
450
459
|
// cell
|
|
451
460
|
gridCellBgColor: slateDark.slate2,
|
|
452
|
-
gridCellBorderColor: slateDark.
|
|
461
|
+
gridCellBorderColor: slateDark.slate6,
|
|
453
462
|
gridPinnedCellBorderColor: slateDark.slate8,
|
|
454
463
|
gridDisabledCellBgColor: slateDark.slate3,
|
|
455
464
|
gridSelectedCellBgColor: indigoDark.indigo3,
|
|
456
|
-
|
|
465
|
+
gridHighlightedCellBgColor: indigoDark.indigo5,
|
|
466
|
+
gridSelectedCellBorderColor: indigoDark.indigo7,
|
|
457
467
|
gridSelectedPinnedCellBorderColor: indigoDark.indigo7,
|
|
458
468
|
gridDisabledSelectedCellBgColor: indigoDark.indigo5,
|
|
459
469
|
gridActiveCellBorderColor: indigoDark.indigo9,
|
|
@@ -923,13 +933,6 @@ export const textStyles = {
|
|
|
923
933
|
fontWeight: fontWeight.regular,
|
|
924
934
|
color: themeVars.textColor,
|
|
925
935
|
},
|
|
926
|
-
fake: {
|
|
927
|
-
fontFamily,
|
|
928
|
-
fontSize: typeSizes[7],
|
|
929
|
-
lineHeight: lineHeight.regular,
|
|
930
|
-
fontWeight: fontWeight.regular,
|
|
931
|
-
color: colors.shades.opacity25,
|
|
932
|
-
},
|
|
933
936
|
link: {
|
|
934
937
|
color: themeVars.linkColor,
|
|
935
938
|
borderBottom: themeVars.linkBorder,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {EmojiItem} from "@fibery/emoji-data/lib/src";
|
|
2
|
+
import {ColorPicker} from "../ColorPicker";
|
|
3
|
+
import {$TSFixMe} from "../tsfixme";
|
|
4
|
+
import {LazyIconDataStore} from "./stores/lazy-icon-data-store";
|
|
5
|
+
import {EmojiPickerContent} from "./primitives/content";
|
|
6
|
+
import {EmojiPickerFooter} from "./primitives/footer";
|
|
7
|
+
import {EmojiPickerGrid} from "./primitives/grid";
|
|
8
|
+
import {EmojiPickerHeader} from "./primitives/header";
|
|
9
|
+
import {EmojiPickerRoot} from "./primitives/root";
|
|
10
|
+
import {EmojiPickerSearch} from "./primitives/search";
|
|
11
|
+
import {cardTypeColors} from "../designSystem";
|
|
12
|
+
|
|
13
|
+
const i18n = {search: "Search icon...", notfound: "No Icons Found"};
|
|
14
|
+
|
|
15
|
+
export type AppIconPickerProps = {
|
|
16
|
+
color?: string;
|
|
17
|
+
getHoverColor?: (color: string) => string | undefined;
|
|
18
|
+
colors?: string[];
|
|
19
|
+
onColorSelect?: (c: $TSFixMe) => void;
|
|
20
|
+
|
|
21
|
+
onSelect: (emoji: EmojiItem) => void;
|
|
22
|
+
};
|
|
23
|
+
export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
24
|
+
onSelect,
|
|
25
|
+
color,
|
|
26
|
+
colors = cardTypeColors,
|
|
27
|
+
onColorSelect,
|
|
28
|
+
getHoverColor,
|
|
29
|
+
}) => {
|
|
30
|
+
return (
|
|
31
|
+
<EmojiPickerRoot i18n={i18n} onEmojiSelect={onSelect}>
|
|
32
|
+
<EmojiPickerContent emojiHoverColor={color ? getHoverColor?.(color) : undefined} emojiSize={20}>
|
|
33
|
+
<LazyIconDataStore fallback={<div style={{height: "282px"}}></div>}>
|
|
34
|
+
<EmojiPickerHeader>
|
|
35
|
+
<EmojiPickerSearch autoFocus />
|
|
36
|
+
</EmojiPickerHeader>
|
|
37
|
+
|
|
38
|
+
<EmojiPickerGrid />
|
|
39
|
+
</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
|
+
</EmojiPickerContent>
|
|
52
|
+
</EmojiPickerRoot>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {makeEmojiData} from "@fibery/emoji-data";
|
|
2
|
+
|
|
3
|
+
import data from "@fibery/emoji-data/data/all.json";
|
|
4
|
+
|
|
5
|
+
import {getEmojiSet} from "./utils/emoji-set";
|
|
6
|
+
|
|
7
|
+
// TODO: remove it. Emoji Data should not be accesed like this, prefer consuming it from context
|
|
8
|
+
export const emojiIndex = makeEmojiData(data, {set: getEmojiSet()});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {EmojiItem} from "@fibery/emoji-data/lib/src";
|
|
2
|
+
import {$TSFixMe} from "../tsfixme";
|
|
3
|
+
import {EmojiPickerRoot} from "./primitives/root";
|
|
4
|
+
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
|
+
import {EmojiPickerFooter} from "./primitives/footer";
|
|
12
|
+
import {cardTypeColors} from "../designSystem";
|
|
13
|
+
|
|
14
|
+
const i18n = {search: "Search emoji..."};
|
|
15
|
+
|
|
16
|
+
export type EmojiPickerProps = {
|
|
17
|
+
color?: string;
|
|
18
|
+
getHoverColor?: (color: string) => string | undefined;
|
|
19
|
+
colors?: string[];
|
|
20
|
+
onColorSelect?: (c: $TSFixMe) => void;
|
|
21
|
+
onCustomCategorySettings?: () => void;
|
|
22
|
+
onSelect: (emoji: EmojiItem) => void;
|
|
23
|
+
showSkinTones?: boolean;
|
|
24
|
+
|
|
25
|
+
searchRef?: React.RefObject<HTMLInputElement>;
|
|
26
|
+
};
|
|
27
|
+
export const EmojiPicker: React.FC<EmojiPickerProps> = ({
|
|
28
|
+
onSelect,
|
|
29
|
+
color,
|
|
30
|
+
colors = cardTypeColors,
|
|
31
|
+
onColorSelect,
|
|
32
|
+
onCustomCategorySettings,
|
|
33
|
+
getHoverColor,
|
|
34
|
+
showSkinTones,
|
|
35
|
+
searchRef,
|
|
36
|
+
}) => {
|
|
37
|
+
return (
|
|
38
|
+
<EmojiPickerRoot i18n={i18n} onEmojiSelect={onSelect} onCustomCategorySettings={onCustomCategorySettings}>
|
|
39
|
+
<EmojiPickerContent emojiHoverColor={color ? getHoverColor?.(color) : undefined} emojiSize={20}>
|
|
40
|
+
<EmojiPickerHeader>
|
|
41
|
+
<EmojiPickerSearch
|
|
42
|
+
searchRef={searchRef}
|
|
43
|
+
autoFocus
|
|
44
|
+
className={cx(
|
|
45
|
+
showSkinTones &&
|
|
46
|
+
css`
|
|
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 />
|
|
63
|
+
|
|
64
|
+
{onColorSelect ? (
|
|
65
|
+
<EmojiPickerFooter>
|
|
66
|
+
<ColorPicker
|
|
67
|
+
colors={colors}
|
|
68
|
+
getSwatchHoverColor={getHoverColor}
|
|
69
|
+
color={color}
|
|
70
|
+
onChangeComplete={onColorSelect}
|
|
71
|
+
/>
|
|
72
|
+
</EmojiPickerFooter>
|
|
73
|
+
) : null}
|
|
74
|
+
</EmojiPickerContent>
|
|
75
|
+
</EmojiPickerRoot>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {Emoji as EmojiPrimitive, EmojiProps as EmojiPrimitiveProps} from "./primitives/emoji";
|
|
2
|
+
import {isApple} from "./utils/emoji-set";
|
|
3
|
+
import {detectEmojiSupportLevel} from "./utils/emoji-support";
|
|
4
|
+
|
|
5
|
+
export type EmojiProps = EmojiPrimitiveProps;
|
|
6
|
+
export const Emoji: React.FC<EmojiPrimitiveProps> = (props) => {
|
|
7
|
+
return <EmojiPrimitive version={detectEmojiSupportLevel()} native={isApple()} {...props} />;
|
|
8
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
|
+
import {compact} from "lodash";
|
|
2
3
|
import {Button} from "../Button";
|
|
3
4
|
import {AntTabs} from "../antd";
|
|
4
5
|
import {space, textStyles} from "../designSystem";
|
|
@@ -16,14 +17,19 @@ const TabHeader: React.FC<React.PropsWithChildren> = ({children}) => (
|
|
|
16
17
|
</div>
|
|
17
18
|
);
|
|
18
19
|
|
|
19
|
-
type
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
type TabKey = "icons" | "emojis";
|
|
21
|
+
|
|
22
|
+
export type IconEmojiPickerProps = React.PropsWithChildren<{
|
|
23
|
+
onIconSelect?: AppIconPickerProps["onSelect"];
|
|
24
|
+
onEmojiSelect?: EmojiPickerProps["onSelect"];
|
|
22
25
|
onColorSelect?: (c: $TSFixMe) => void;
|
|
26
|
+
onCreateClick?: () => void;
|
|
27
|
+
onCustomEmojisSettings?: () => void;
|
|
23
28
|
onReset?: () => void;
|
|
24
29
|
resetLabel?: string;
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
createLabel?: string;
|
|
31
|
+
defaultTab?: TabKey;
|
|
32
|
+
showColorPickerOnTabs?: TabKey[];
|
|
27
33
|
color?: string;
|
|
28
34
|
getHoverColor?: (color: string) => string | undefined;
|
|
29
35
|
}>;
|
|
@@ -31,8 +37,11 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
31
37
|
onIconSelect,
|
|
32
38
|
onEmojiSelect,
|
|
33
39
|
onColorSelect,
|
|
40
|
+
onCreateClick,
|
|
41
|
+
onCustomEmojisSettings,
|
|
34
42
|
defaultTab,
|
|
35
43
|
onReset,
|
|
44
|
+
createLabel = "Add Emoji",
|
|
36
45
|
resetLabel = "Reset",
|
|
37
46
|
showColorPickerOnTabs = ["icons", "emojis"],
|
|
38
47
|
color,
|
|
@@ -43,26 +52,39 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
43
52
|
animated={false}
|
|
44
53
|
destroyInactiveTabPane
|
|
45
54
|
defaultActiveKey={defaultTab}
|
|
46
|
-
items={[
|
|
47
|
-
{
|
|
55
|
+
items={compact([
|
|
56
|
+
onEmojiSelect && {
|
|
48
57
|
key: "emojis",
|
|
49
58
|
label: <TabHeader>Emojis</TabHeader>,
|
|
50
59
|
children: (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
<>
|
|
61
|
+
<EmojiPicker
|
|
62
|
+
color={color}
|
|
63
|
+
onColorSelect={showColorPickerOnTabs.includes("emojis") ? onColorSelect : undefined}
|
|
64
|
+
onCustomCategorySettings={onCustomEmojisSettings}
|
|
65
|
+
getHoverColor={getHoverColor}
|
|
66
|
+
onSelect={onEmojiSelect}
|
|
67
|
+
showSkinTones
|
|
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
|
+
</>
|
|
58
81
|
),
|
|
59
82
|
},
|
|
60
|
-
{
|
|
83
|
+
onIconSelect && {
|
|
61
84
|
key: "icons",
|
|
62
85
|
label: <TabHeader>Icons</TabHeader>,
|
|
63
86
|
children: (
|
|
64
87
|
<AppIconPicker
|
|
65
|
-
autoFocus
|
|
66
88
|
color={color}
|
|
67
89
|
onColorSelect={showColorPickerOnTabs.includes("icons") ? onColorSelect : undefined}
|
|
68
90
|
getHoverColor={getHoverColor}
|
|
@@ -70,7 +92,7 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
70
92
|
/>
|
|
71
93
|
),
|
|
72
94
|
},
|
|
73
|
-
]}
|
|
95
|
+
])}
|
|
74
96
|
tabBarExtraContent={
|
|
75
97
|
onReset ? (
|
|
76
98
|
<div
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {Category} from "@fibery/emoji-data";
|
|
2
|
+
import {CSSProperties, css} from "@linaria/core";
|
|
3
|
+
import {memo} from "react";
|
|
4
|
+
import {IconButton} from "../../Button/icon-button";
|
|
5
|
+
import {space, textStyles, themeVars} from "../../designSystem";
|
|
6
|
+
import {Settings} from "../../icons/react";
|
|
7
|
+
import {useEmojiPickerContentSettings} from "./content";
|
|
8
|
+
import {Emoji} from "./emoji";
|
|
9
|
+
import {emojiPadding} from "./layout";
|
|
10
|
+
import {useEmojiPickerCtx, useEmojiPickerI18N} from "./root";
|
|
11
|
+
import {useEmojiSkin} from "./skin-provider";
|
|
12
|
+
|
|
13
|
+
const categoryCss = css``;
|
|
14
|
+
|
|
15
|
+
const categoryLabelCss = css`
|
|
16
|
+
${textStyles.heading6}
|
|
17
|
+
color: ${themeVars.accentTextColor};
|
|
18
|
+
background-color: ${themeVars.actionMenuBg};
|
|
19
|
+
padding: ${space.l}px ${space.s}px ${space.xs}px ${space.s}px;
|
|
20
|
+
position: sticky;
|
|
21
|
+
top: 0;
|
|
22
|
+
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: ${space.xs}px;
|
|
26
|
+
|
|
27
|
+
/* is required only because contentVisibility lifts emoji up */
|
|
28
|
+
z-index: 1;
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const categoryListCss = css`
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-wrap: wrap;
|
|
34
|
+
margin: 0;
|
|
35
|
+
padding: 0;
|
|
36
|
+
|
|
37
|
+
& li {
|
|
38
|
+
list-style: none;
|
|
39
|
+
margin: 0;
|
|
40
|
+
padding: 0;
|
|
41
|
+
|
|
42
|
+
line-height: 1;
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
const notFoundCss = css`
|
|
47
|
+
padding-top: 70px;
|
|
48
|
+
text-align: center;
|
|
49
|
+
|
|
50
|
+
${textStyles.regular};
|
|
51
|
+
color: ${themeVars.accentTextColor};
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
const NotFound = () => {
|
|
55
|
+
const i18n = useEmojiPickerI18N();
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className={notFoundCss}>
|
|
59
|
+
<Emoji emoji="sleuth_or_spy" size={38} />
|
|
60
|
+
<div>{i18n.notfound}</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type EmojiPickerCategoryProps = {
|
|
66
|
+
category: Category;
|
|
67
|
+
};
|
|
68
|
+
export const EmojiPickerCategory = memo<EmojiPickerCategoryProps>(function EmojiPickerCategoryComponent({category}) {
|
|
69
|
+
const i18n = useEmojiPickerI18N();
|
|
70
|
+
const emojiPickerCtx = useEmojiPickerCtx();
|
|
71
|
+
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
72
|
+
|
|
73
|
+
const label = i18n.categories[category.id as keyof (typeof i18n)["categories"]] || category.name;
|
|
74
|
+
|
|
75
|
+
const skin = useEmojiSkin();
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<section className={categoryCss} aria-label={label}>
|
|
79
|
+
<div className={categoryLabelCss}>
|
|
80
|
+
<span aria-hidden={true /* already labeled by the section aria-label */}>{label}</span>
|
|
81
|
+
{category.id === "custom" && emojiPickerCtx.onCustomCategorySettings && (
|
|
82
|
+
<IconButton onClick={emojiPickerCtx.onCustomCategorySettings}>
|
|
83
|
+
<Settings iconSize={16} />
|
|
84
|
+
</IconButton>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
{category.emojis.length > 0 ? (
|
|
89
|
+
<ul className={categoryListCss}>
|
|
90
|
+
{category.emojis.map((id) => {
|
|
91
|
+
return (
|
|
92
|
+
<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
|
+
key={id}
|
|
101
|
+
>
|
|
102
|
+
<Emoji
|
|
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
|
+
/>
|
|
111
|
+
</li>
|
|
112
|
+
);
|
|
113
|
+
})}
|
|
114
|
+
</ul>
|
|
115
|
+
) : (
|
|
116
|
+
<NotFound />
|
|
117
|
+
)}
|
|
118
|
+
</section>
|
|
119
|
+
);
|
|
120
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {createContext} from "@fibery/react/src/create-context";
|
|
2
|
+
import {CSSProperties, css} from "@linaria/core";
|
|
3
|
+
import {useMemo} from "react";
|
|
4
|
+
import {themeVars} from "../../designSystem";
|
|
5
|
+
import {contentHorizontalPadding, emojiPadding} from "./layout";
|
|
6
|
+
|
|
7
|
+
const emojiPickerCss = css`
|
|
8
|
+
background-color: ${themeVars.actionMenuBg};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
type EmojiPickerContentSettings = {
|
|
12
|
+
perLine: number;
|
|
13
|
+
emojiSize: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const [Provider, useCtx] = createContext<EmojiPickerContentSettings>("EmojiPickerContentSettings");
|
|
17
|
+
|
|
18
|
+
export type EmojiPickerContentProps = {
|
|
19
|
+
emojiHoverColor?: string;
|
|
20
|
+
perLine?: number;
|
|
21
|
+
emojiSize?: number;
|
|
22
|
+
};
|
|
23
|
+
export const EmojiPickerContent: React.FC<React.PropsWithChildren<EmojiPickerContentProps>> = ({
|
|
24
|
+
emojiHoverColor,
|
|
25
|
+
perLine = 9,
|
|
26
|
+
emojiSize = 20,
|
|
27
|
+
children,
|
|
28
|
+
}) => {
|
|
29
|
+
const width = perLine * (emojiSize + emojiPadding * 2) + contentHorizontalPadding * 2;
|
|
30
|
+
|
|
31
|
+
const contentSettings = useMemo(
|
|
32
|
+
() => ({
|
|
33
|
+
emojiSize,
|
|
34
|
+
perLine,
|
|
35
|
+
}),
|
|
36
|
+
[emojiSize, perLine]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Provider value={contentSettings}>
|
|
41
|
+
<div style={{"--fibery-emoji-hover-color": emojiHoverColor, width} as CSSProperties} className={emojiPickerCss}>
|
|
42
|
+
{children}
|
|
43
|
+
</div>
|
|
44
|
+
</Provider>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const useEmojiPickerContentSettings = useCtx;
|