@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.
Files changed (53) hide show
  1. package/package.json +7 -9
  2. package/src/antd/styles.ts +20 -3
  3. package/src/designSystem.ts +14 -11
  4. package/src/emoji-picker/app-icon-picker.tsx +54 -0
  5. package/src/emoji-picker/emoji-index.ts +8 -0
  6. package/src/emoji-picker/emoji-picker.tsx +77 -0
  7. package/src/emoji-picker/emoji.tsx +8 -0
  8. package/src/{emoji-mart → emoji-picker}/icon-emoji-picker.tsx +39 -17
  9. package/src/emoji-picker/index.tsx +5 -0
  10. package/src/emoji-picker/primitives/category.tsx +120 -0
  11. package/src/emoji-picker/primitives/content.tsx +48 -0
  12. package/src/emoji-picker/primitives/emoji.tsx +131 -0
  13. package/src/emoji-picker/primitives/footer.tsx +12 -0
  14. package/src/emoji-picker/primitives/grid.tsx +67 -0
  15. package/src/emoji-picker/primitives/header.tsx +11 -0
  16. package/src/emoji-picker/primitives/layout.ts +5 -0
  17. package/src/emoji-picker/primitives/root.tsx +89 -0
  18. package/src/emoji-picker/primitives/search-provider.tsx +22 -0
  19. package/src/emoji-picker/primitives/search.tsx +141 -0
  20. package/src/emoji-picker/primitives/skin-provider.tsx +27 -0
  21. package/src/emoji-picker/primitives/skin-tone.tsx +103 -0
  22. package/src/emoji-picker/stores/emoji-data-store.tsx +50 -0
  23. package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +29 -0
  24. package/src/emoji-picker/stores/lazy-icon-data-store.tsx +55 -0
  25. package/src/emoji-picker/stores/static-emoji-data-store.tsx +16 -0
  26. package/src/emoji-picker/utils/emoji-set.ts +5 -0
  27. package/src/{emoji-mart → emoji-picker/utils}/emoji-support.ts +6 -10
  28. package/src/emoji-picker/utils/frequently.ts +82 -0
  29. package/src/emoji-picker/utils/load-emoji-data.ts +4 -0
  30. package/src/emoji-picker/utils/store.ts +40 -0
  31. package/src/icons/ast/AddAfter.ts +8 -0
  32. package/src/icons/ast/AddBefore.ts +8 -0
  33. package/src/icons/ast/ArrowBarLeft.ts +8 -0
  34. package/src/icons/ast/ArrowBarRight.ts +8 -0
  35. package/src/icons/ast/Columns2.ts +8 -0
  36. package/src/icons/ast/Columns4.ts +8 -0
  37. package/src/icons/ast/LineDivider.ts +8 -0
  38. package/src/icons/ast/index.tsx +7 -0
  39. package/src/icons/react/AddAfter.tsx +12 -0
  40. package/src/icons/react/AddBefore.tsx +12 -0
  41. package/src/icons/react/ArrowBarLeft.tsx +12 -0
  42. package/src/icons/react/ArrowBarRight.tsx +12 -0
  43. package/src/icons/react/Columns2.tsx +12 -0
  44. package/src/icons/react/Columns4.tsx +12 -0
  45. package/src/icons/react/LineDivider.tsx +12 -0
  46. package/src/icons/react/index.tsx +7 -0
  47. package/src/emoji-mart/app-icon-picker.tsx +0 -68
  48. package/src/emoji-mart/data/get-data.tsx +0 -58
  49. package/src/emoji-mart/emoji/emoji.tsx +0 -26
  50. package/src/emoji-mart/emoji/index.tsx +0 -24
  51. package/src/emoji-mart/emoji-index.ts +0 -5
  52. package/src/emoji-mart/emoji-mart.tsx +0 -216
  53. 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.13.0",
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-mart/**/*.ts*",
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/emoji-data": "1.1.2",
64
- "@fibery/helpers": "1.0.4",
65
- "@fibery/react": "1.0.2"
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/babel-preset": "7.2.0",
99
- "@fibery/eslint-config": "8.3.0"
96
+ "@fibery/eslint-config": "8.3.0",
97
+ "@fibery/babel-preset": "7.2.0"
100
98
  },
101
99
  "jest": {
102
100
  "testEnvironment": "jsdom",
@@ -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: themeVars.inputBorderColor,
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: `0 0 0 1px ${themeVars.opacity.opacity40} !important`,
42
+ boxShadow: "var(--input-hover-border) !important",
27
43
  transition: `box-shadow ${transition}`,
28
44
  },
29
45
  focus: {
30
- boxShadow: `0 0 0 1px ${themeVars.opacity.opacity25}, 0 0 0 3px ${themeVars.focus} !important`,
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"},
@@ -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.slate4,
276
+ gridCellBorderColor: slate.slate5,
273
277
  gridPinnedCellBorderColor: slate.slate8,
274
278
  gridDisabledCellBgColor: slate.slate2,
275
279
  gridSelectedCellBgColor: indigo.indigo3,
276
- gridSelectedCellBorderColor: indigo.indigo5,
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.slate5,
461
+ gridCellBorderColor: slateDark.slate6,
453
462
  gridPinnedCellBorderColor: slateDark.slate8,
454
463
  gridDisabledCellBgColor: slateDark.slate3,
455
464
  gridSelectedCellBgColor: indigoDark.indigo3,
456
- gridSelectedCellBorderColor: indigoDark.indigo6,
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 IconEmojiPickerProps = React.PropsWithChildren<{
20
- onIconSelect: NonNullable<AppIconPickerProps["onSelect"]>;
21
- onEmojiSelect: NonNullable<EmojiPickerProps["onSelect"]>;
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
- defaultTab?: "icons" | "emojis";
26
- showColorPickerOnTabs?: ("icons" | "emojis")[];
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
- <EmojiPicker
52
- autoFocus
53
- color={color}
54
- onColorSelect={showColorPickerOnTabs.includes("emojis") ? onColorSelect : undefined}
55
- getHoverColor={getHoverColor}
56
- onSelect={onEmojiSelect}
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,5 @@
1
+ export {EmojiPickerRoot as Root} from "./root";
2
+ export {EmojiPickerContent as Content} from "./content";
3
+ export {EmojiPickerGrid as Grid} from "./grid";
4
+ export {EmojiPickerSearch as Search} from "./search";
5
+ export {EmojiPickerFooter as Footer} from "./footer";
@@ -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;