@fibery/ui-kit 1.21.1 → 1.23.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fibery/ui-kit",
3
- "version": "1.21.1",
3
+ "version": "1.23.0",
4
4
  "main": "index.ts",
5
5
  "private": false,
6
6
  "files": [
@@ -21,6 +21,7 @@
21
21
  "src/error-alert.tsx",
22
22
  "src/pallete.ts",
23
23
  "src/tooltip.tsx",
24
+ "src/tooltip-if-overflown.tsx",
24
25
  "src/back-button.tsx",
25
26
  "src/button",
26
27
  "src/emoji-picker/**/*.ts*",
@@ -68,7 +69,7 @@
68
69
  "react-windowed-select": "5.0.0",
69
70
  "screenfull": "6.0.1",
70
71
  "ua-parser-js": "0.7.24",
71
- "@fibery/emoji-data": "2.2.1",
72
+ "@fibery/emoji-data": "2.3.0",
72
73
  "@fibery/helpers": "1.2.0",
73
74
  "@fibery/react": "1.3.0"
74
75
  },
@@ -103,8 +104,8 @@
103
104
  "svgo": "2.8.0",
104
105
  "typescript": "5.1.6",
105
106
  "unist-util-reduce": "0.2.2",
106
- "@fibery/babel-preset": "7.3.0",
107
- "@fibery/eslint-config": "8.5.0"
107
+ "@fibery/eslint-config": "8.5.0",
108
+ "@fibery/babel-preset": "7.3.0"
108
109
  },
109
110
  "jest": {
110
111
  "testEnvironment": "jsdom",
@@ -124,7 +125,24 @@
124
125
  "createInlineTheme\\.js$": "<rootDir>/src/__mocks__/createInlineTheme.js"
125
126
  },
126
127
  "transform": {
127
- "^.+\\.(js|jsx|ts|tsx)$": "babel-jest"
128
+ "^.+\\.(js|jsx|ts|tsx)$": [
129
+ "@swc/jest",
130
+ {
131
+ "jsc": {
132
+ "parser": {
133
+ "syntax": "typescript",
134
+ "tsx": true,
135
+ "decorators": true,
136
+ "dynamicImport": true
137
+ },
138
+ "transform": {
139
+ "react": {
140
+ "runtime": "automatic"
141
+ }
142
+ }
143
+ }
144
+ }
145
+ ]
128
146
  },
129
147
  "setupFilesAfterEnv": [
130
148
  "<rootDir>/config/jest/testFrameworkSetup.js"
@@ -12,6 +12,8 @@ import {
12
12
  redDark,
13
13
  slate,
14
14
  slateDark,
15
+ teal,
16
+ tealDark,
15
17
  whiteA,
16
18
  yellow,
17
19
  yellowDark,
@@ -376,6 +378,12 @@ export const themeColors = {
376
378
  relationViewBgColor: [slate.slate2, slateDark.slate3],
377
379
  unitBg: [slate.slate3, slateDark.slate6],
378
380
  unitBgHover: [slate.slate4, slateDark.slate7],
381
+ colorBgBadgeSuccess: [teal.teal5, tealDark.teal5],
382
+ colorBgBadgeWarning: [yellow.yellow5, yellowDark.yellow5],
383
+ colorBgBadgeError: [red.red5, redDark.red5],
384
+ colorTextBadgeSuccess: [teal.teal11, tealDark.teal11],
385
+ colorTextBadgeWarning: [yellow.yellow11, yellowDark.yellow11],
386
+ colorTextBadgeError: [red.red11, redDark.red11],
379
387
  badgeBgColor: [getOpacities(slate.slate10).opacity20, getOpacities(slate.slate10).opacity20],
380
388
  panelBadgeBgColor: [getOpacities(slate.slate10).opacity20, getOpacities(slate.slate10).opacity20],
381
389
  tooltipBgColor: [slateDark.slate5, slateDark.slate6],
@@ -449,6 +457,8 @@ export const themeColors = {
449
457
  progressText: [slate.slate11, slate.slate11],
450
458
  progressFillBg: [slate.slate11, slate.slate11],
451
459
  progressFillText: [whiteA.whiteA0, whiteA.whiteA0],
460
+ progressBarFill: [indigo.indigo9, indigoDark.indigo10],
461
+ progressBarBg: [getOpacities(indigo.indigo9).opacity25, getOpacities(indigoDark.indigo10).opacity25],
452
462
  searchFiltersBg: [slate.slate1, slateDark.slate2],
453
463
  colorPickerSwatchBorder: [blackA.blackA7, blackA.blackA7],
454
464
  richTextTableBorder: [blackA.blackA5, whiteA.whiteA7],
@@ -475,6 +485,7 @@ export const themeColors = {
475
485
  colorTextReactionsSelected: [indigo.indigo10, slateDark.slate12],
476
486
  colorBgToastDefault: [slate.slate1, slateDark.slate1],
477
487
  colorBgDbTabHover: [slate.slate3, slateDark.slate4],
488
+ colorBgDbTabFocus: [slate.slate6, slateDark.slate6],
478
489
  } as const;
479
490
 
480
491
  type ThemeDefs = typeof themeColors;
@@ -735,6 +746,8 @@ export const spaceNestedTreeInterval = 0;
735
746
  export const layout = {
736
747
  logoSize: 16,
737
748
  menuDefaultWidth: 243,
749
+ desktopToolbarHeight: 32,
750
+ desktopMenuMinWidth: 160,
738
751
  menuMinWidth: 47, //TODO: make dependency to itemHeight
739
752
  menuMaxWidth: 480,
740
753
  menuItemMinWidth: 80,
@@ -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";
@@ -4,7 +4,7 @@ import {memo} from "react";
4
4
  import {useInView} from "react-intersection-observer";
5
5
  import {IconButton} from "../../button/icon-button";
6
6
  import {space, textStyles, themeVars} from "../../design-system";
7
- import {Settings} from "../../icons/react";
7
+ import Settings from "../../icons/react/Settings";
8
8
  import {useEmojiDataStoreSelector} from "../stores/emoji-data-store";
9
9
  import {useEmojiPickerContentSettings} from "./content";
10
10
  import {Emoji} from "./emoji";
@@ -6,7 +6,7 @@ import {useEmojiDataStoreSelector} from "../stores/emoji-data-store";
6
6
 
7
7
  const emojiWrapperCss = css`
8
8
  color: ${themeVars.textColor};
9
- font-family: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla",
9
+ font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Twemoji Mozilla",
10
10
  "Noto Color Emoji", "Android Emoji";
11
11
  line-height: 1;
12
12
  `;
@@ -19,7 +19,9 @@ type AllCategoriesProps = Pick<EmojiPickerCategoryProps, "renderEmoji" | "scroll
19
19
  const AllCategories: React.FC<AllCategoriesProps> = ({renderEmoji, scrollParent}) => {
20
20
  const contentSettings = useEmojiPickerContentSettings();
21
21
 
22
+ // TODO: accessing emojiData inside useMemo is not reactive so it won't be re-rendered when emojis are modified
22
23
  const emojiData = useEmojiDataStore();
24
+
23
25
  const categories = useEmojiDataStoreSelector((store) => store.getCategories());
24
26
 
25
27
  const recentCategory = useMemo(
@@ -3,7 +3,7 @@ import {space} from "../../design-system";
3
3
  import {contentHorizontalPadding} from "./layout";
4
4
 
5
5
  const pickerHeader = css`
6
- padding: ${space.s6}px ${contentHorizontalPadding}px;
6
+ padding: ${space.s12}px ${contentHorizontalPadding}px ${space.s6}px ${contentHorizontalPadding}px;
7
7
  position: relative;
8
8
  `;
9
9
  export const EmojiPickerHeader: React.FC<React.PropsWithChildren> = ({children}) => {
@@ -1,7 +1,7 @@
1
1
  import type {EmojiData} from "@fibery/emoji-data";
2
2
  import {PubSub, makePubSub} from "@fibery/helpers/utils/pub-sub";
3
3
  import {createContext} from "@fibery/react/src/create-context";
4
- import {useMemo, useSyncExternalStore} from "react";
4
+ import {useSyncExternalStore} from "react";
5
5
 
6
6
  export type EmojiDataStore = EmojiData & {pubSub: PubSub};
7
7
 
@@ -11,6 +11,10 @@ export const makeEmojiDataStore = (emojiData: EmojiData): EmojiDataStore => {
11
11
  return {
12
12
  ...emojiData,
13
13
 
14
+ setData(...args: Parameters<EmojiData["setData"]>) {
15
+ emojiData.setData(...args);
16
+ pubSub.publish();
17
+ },
14
18
  setCustom(...args: Parameters<EmojiData["setCustom"]>) {
15
19
  emojiData.setCustom(...args);
16
20
  pubSub.publish();
@@ -30,20 +34,19 @@ export const makeEmojiDataStore = (emojiData: EmojiData): EmojiDataStore => {
30
34
 
31
35
  const [DataStoreProvider, useDataStoreCtx] = createContext<EmojiDataStore>("EmojiDataStore");
32
36
 
33
- export const EmojiDataStoreProvider: React.FC<
34
- React.PropsWithChildren<{
35
- data: EmojiData;
36
- }>
37
- > = ({data, children}) => {
38
- const emojiDataStore = useMemo(() => makeEmojiDataStore(data), [data]);
39
-
40
- return <DataStoreProvider value={emojiDataStore}>{children}</DataStoreProvider>;
41
- };
37
+ export const EmojiDataStoreProvider = DataStoreProvider;
42
38
 
43
39
  export const useEmojiDataStore = useDataStoreCtx;
44
40
 
41
+ // TODO: this https://github.com/facebook/react/blob/main/packages/use-sync-external-store/with-selector.js can be used
42
+ // for more flexible selections (e.g. getManyEmojis(ids: string[]){})
43
+ // but it's not documented by react yet. Even though react-redux uses it in useSelector
45
44
  export const useEmojiDataStoreSelector = <Snapshot,>(getter: (emojiDataStore: EmojiDataStore) => Snapshot) => {
46
45
  const dataStore = useDataStoreCtx();
47
46
 
48
47
  return useSyncExternalStore(dataStore.pubSub.subscribe, () => getter(dataStore));
49
48
  };
49
+
50
+ const getIsInitialized = (store: EmojiDataStore) => store.getIsInitialized();
51
+
52
+ export const useIsInitializedEmojiDataStore = () => useEmojiDataStoreSelector(getIsInitialized);
@@ -1,6 +1,6 @@
1
1
  import {RawCustomEmoji, makeEmojiData} from "@fibery/emoji-data";
2
2
  import {Suspense, lazy} from "react";
3
- import {EmojiDataStoreProvider} from "./emoji-data-store";
3
+ import {EmojiDataStoreProvider, makeEmojiDataStore} from "./emoji-data-store";
4
4
  import {getImageUrl} from "../../app-icon-with-fallback";
5
5
 
6
6
  const EMPTY_DATA = {
@@ -24,9 +24,11 @@ const LazyAppIcons = lazy(async () => {
24
24
 
25
25
  appIconsEmojiData.setCustom(custom);
26
26
 
27
+ const appIconsEmojiStore = makeEmojiDataStore(appIconsEmojiData);
28
+
27
29
  return {
28
30
  default: function EmojiDataStore({children}: React.PropsWithChildren) {
29
- return <EmojiDataStoreProvider data={appIconsEmojiData}>{children}</EmojiDataStoreProvider>;
31
+ return <EmojiDataStoreProvider value={appIconsEmojiStore}>{children}</EmojiDataStoreProvider>;
30
32
  },
31
33
  };
32
34
  });
@@ -1,16 +1,21 @@
1
- import {FC, ReactNode, useMemo} from "react";
2
1
  import {makeEmojiData} from "@fibery/emoji-data";
3
- import {getEmojiSet} from "../utils/emoji-set";
4
- import {EmojiDataStoreProvider} from "./emoji-data-store";
5
2
  import rawData from "@fibery/emoji-data/data/all.json";
6
-
7
- // Static means "preloaded", "non-lazy" here
3
+ import {FC, ReactNode, useMemo} from "react";
4
+ import {getEmojiSet} from "../utils/emoji-set";
5
+ import {EmojiDataStoreProvider, makeEmojiDataStore} from "./emoji-data-store";
8
6
 
9
7
  interface EmojiDataProviderProps {
10
8
  children?: ReactNode;
11
9
  }
12
10
 
11
+ /**
12
+ * @deprecated
13
+ * Static means "preloaded", "non-lazy" here
14
+ * Should Not outside of tests
15
+ */
13
16
  export const StaticEmojiDataStore: FC<EmojiDataProviderProps> = ({children}) => {
14
17
  const emojiData = useMemo(() => makeEmojiData(rawData, {set: getEmojiSet()}), []);
15
- return <EmojiDataStoreProvider data={emojiData}>{children}</EmojiDataStoreProvider>;
18
+ const emojiDataStore = useMemo(() => makeEmojiDataStore(emojiData), [emojiData]);
19
+
20
+ return <EmojiDataStoreProvider value={emojiDataStore}>{children}</EmojiDataStoreProvider>;
16
21
  };
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const Chat: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"viewBox":"0 0 20 20"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","clipRule":"evenodd","d":"M8.854 3.524a.083.083 0 0 1 .06-.024h7.5a.083.083 0 0 1 .083.083v6.523l-1.22-1.22a.75.75 0 0 0-.53-.22H8.913a.083.083 0 0 1-.083-.083v-5c0-.022.009-.043.024-.059ZM8.914 2A1.583 1.583 0 0 0 7.33 3.583v5a1.583 1.583 0 0 0 1.583 1.584h5.523l2.28 2.28a.75.75 0 0 0 1.28-.53V3.583A1.583 1.583 0 0 0 16.414 2h-7.5Zm-5.39 6.854a.083.083 0 0 1 .06-.024H5.25a.75.75 0 0 0 0-1.5H3.583A1.583 1.583 0 0 0 2 8.913v8.334a.75.75 0 0 0 1.28.53l2.28-2.28h5.523a1.583 1.583 0 0 0 1.584-1.584v-1.666a.75.75 0 0 0-1.5 0v1.666a.083.083 0 0 1-.084.084H5.25a.75.75 0 0 0-.53.22L3.5 15.435V8.913c0-.022.009-.043.024-.059Z"},"children":[]}],"metadata":""}]},"name":"chat"};
7
+
8
+ export default Chat;
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const ChatAi: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"viewBox":"0 0 20 20"},"children":[{"type":"element","tagName":"path","properties":{"d":"M11.263.181a.281.281 0 0 0-.526 0l-.57 1.498a.844.844 0 0 1-.488.488l-1.498.57a.281.281 0 0 0 0 .526l1.498.57a.844.844 0 0 1 .488.488l.57 1.498a.281.281 0 0 0 .526 0l.57-1.498a.844.844 0 0 1 .488-.488l1.498-.57a.281.281 0 0 0 0-.526l-1.498-.57a.844.844 0 0 1-.488-.488L11.263.18ZM17 4c.117 0 .221.072.263.181l.57 1.498a.844.844 0 0 0 .488.488l1.498.57a.281.281 0 0 1 0 .526l-1.498.57a.844.844 0 0 0-.488.488l-.57 1.498a.281.281 0 0 1-.526 0l-.57-1.498a.843.843 0 0 0-.488-.488l-1.498-.57a.281.281 0 0 1 0-.526l1.498-.57a.843.843 0 0 0 .488-.488l.57-1.498A.281.281 0 0 1 17 4Z"},"children":[]},{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","clipRule":"evenodd","d":"M11.087 7.33a1.583 1.583 0 0 1 1.583 1.583v5a1.583 1.583 0 0 1-1.583 1.584H5.564l-2.28 2.28a.75.75 0 0 1-1.28-.53V8.913A1.583 1.583 0 0 1 3.586 7.33h7.5Zm.059 1.524a.083.083 0 0 0-.06-.024h-7.5a.083.083 0 0 0-.083.083v6.523l1.22-1.22a.75.75 0 0 1 .53-.22h5.834a.084.084 0 0 0 .083-.083v-5a.083.083 0 0 0-.024-.059Z"},"children":[]}],"metadata":""}]},"name":"chat-ai"};
7
+
8
+ export default ChatAi;
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const Headphones: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"viewBox":"0 0 20 20"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","clipRule":"evenodd","d":"M17.626 9.012C17.108 5.055 13.927 2 10 2 6.072 2 2.892 5.056 2.374 9.012c-.154.1-.293.224-.41.367a2.107 2.107 0 0 0-.464 1.335v1.822c0 .479.155.96.464 1.335.312.379.77.629 1.286.629h1.5c.19 0 .365-.071.497-.188C6.037 16.438 7.806 18 10 18s3.963-1.562 4.753-3.688a.75.75 0 0 0 .497.188h1.5c.516 0 .974-.25 1.286-.629.309-.375.464-.856.464-1.335v-1.822c0-.479-.155-.96-.464-1.335a1.795 1.795 0 0 0-.41-.367Zm-1.459-.262C15.566 5.638 13 3.35 10 3.35s-5.566 2.288-6.167 5.4h.916a.751.751 0 0 1 .595.292C6.176 7.042 7.892 5.6 10 5.6c2.108 0 3.824 1.443 4.656 3.442a.75.75 0 0 1 .595-.292h.916ZM10 7c1.974 0 3.8 2.011 3.8 4.8 0 2.789-1.826 4.8-3.8 4.8-1.974 0-3.8-2.011-3.8-4.8C6.2 9.011 8.026 7 10 7Z"},"children":[]}],"metadata":""}]},"name":"headphones"};
7
+
8
+ export default Headphones;
@@ -0,0 +1,8 @@
1
+
2
+ // This icon file is generated automatically.
3
+
4
+ import { IconDefinition } from '../types';
5
+
6
+ const HeadphonesAi: IconDefinition = {"icon":{"type":"root","children":[{"type":"element","tagName":"svg","properties":{"viewBox":"0 0 20 20"},"children":[{"type":"element","tagName":"path","properties":{"d":"m17.833 8.679-.712-1.652C15.973 4.065 13.24 2 10 2 6.759 2 4.027 4.065 2.88 7.027L2.166 8.68a.844.844 0 0 1-.488.488l-1.498.57a.281.281 0 0 0 0 .526l1.498.57a.844.844 0 0 1 .488.488l.57 1.498a.281.281 0 0 0 .526 0l.57-1.498a.844.844 0 0 1 .488-.488l1.498-.57a.281.281 0 0 0 0-.526l-1.498-.57c-.217-.083-.512-.299-.479-.465C4.461 5.614 7.015 3.35 10 3.35c2.985 0 5.54 2.264 6.157 5.352.038.187-.261.382-.478.465l-1.498.57a.281.281 0 0 0 0 .526l1.498.57a.844.844 0 0 1 .488.488l.57 1.498a.281.281 0 0 0 .526 0l.57-1.498a.844.844 0 0 1 .488-.488l1.498-.57a.281.281 0 0 0 0-.526l-1.498-.57a.844.844 0 0 1-.488-.488Z"},"children":[]},{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","clipRule":"evenodd","d":"M10.319 7.265a.562.562 0 0 0-.844.262l-1.015 2.64c-.176.457-.232.592-.31.702a1.194 1.194 0 0 1-.28.281c-.11.077-.245.133-.702.31l-2.64 1.015a.562.562 0 0 0 0 1.05l2.64 1.015c.457.176.592.232.701.31.11.078.204.173.281.281.078.11.134.244.31.701l1.015 2.64a.562.562 0 0 0 1.05 0l1.016-2.64c.175-.457.232-.592.31-.701.077-.109.172-.204.28-.281.11-.078.245-.134.701-.31l2.64-1.015a.561.561 0 0 0 0-1.05l-2.64-1.016c-.456-.175-.591-.232-.7-.31a1.198 1.198 0 0 1-.282-.28c-.077-.11-.134-.245-.31-.701l-1.015-2.64a.562.562 0 0 0-.206-.263Zm-.833 3.37L10 9.294l.514 1.335c.143.372.25.65.42.89.15.211.335.396.546.546.239.17.516.276.886.42l1.339.514-1.336.514c-.372.142-.65.249-.889.42-.211.15-.396.334-.546.545-.169.238-.275.512-.416.88L10 16.703l-.514-1.335c-.142-.373-.249-.65-.42-.89a2.342 2.342 0 0 0-.545-.546c-.24-.17-.517-.277-.889-.42L6.295 13l1.34-.515c.37-.143.647-.25.886-.419.211-.15.396-.335.546-.546.17-.238.276-.515.419-.886Z"},"children":[]}],"metadata":""}]},"name":"headphones-ai"};
7
+
8
+ export default HeadphonesAi;
@@ -41,6 +41,8 @@ export { default as BellRinging } from './BellRinging';
41
41
  export { default as BellX } from './BellX';
42
42
  export { default as Bolt } from './Bolt';
43
43
  export { default as Cards } from './Cards';
44
+ export { default as ChatAi } from './ChatAi';
45
+ export { default as Chat } from './Chat';
44
46
  export { default as CheckCircle } from './CheckCircle';
45
47
  export { default as Checked } from './Checked';
46
48
  export { default as ClearValue } from './ClearValue';
@@ -91,6 +93,8 @@ export { default as GlobeSimple } from './GlobeSimple';
91
93
  export { default as Globe } from './Globe';
92
94
  export { default as GoogleDrive } from './GoogleDrive';
93
95
  export { default as GoogleMap } from './GoogleMap';
96
+ export { default as HeadphonesAi } from './HeadphonesAi';
97
+ export { default as Headphones } from './Headphones';
94
98
  export { default as Hide } from './Hide';
95
99
  export { default as Hint } from './Hint';
96
100
  export { default as Home } from './Home';
@@ -0,0 +1,12 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import ChatSvg from '../ast/Chat';
4
+ import { Icon } from '../Icon';
5
+ import { IconBaseProps } from '../types';
6
+
7
+ const Chat = (
8
+ props: IconBaseProps,
9
+ ): JSX.Element => <Icon {...props} icon={ChatSvg} />;
10
+
11
+ Chat.displayName = 'Chat';
12
+ export default Chat;
@@ -0,0 +1,12 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import ChatAiSvg from '../ast/ChatAi';
4
+ import { Icon } from '../Icon';
5
+ import { IconBaseProps } from '../types';
6
+
7
+ const ChatAi = (
8
+ props: IconBaseProps,
9
+ ): JSX.Element => <Icon {...props} icon={ChatAiSvg} />;
10
+
11
+ ChatAi.displayName = 'ChatAi';
12
+ export default ChatAi;
@@ -0,0 +1,12 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import HeadphonesSvg from '../ast/Headphones';
4
+ import { Icon } from '../Icon';
5
+ import { IconBaseProps } from '../types';
6
+
7
+ const Headphones = (
8
+ props: IconBaseProps,
9
+ ): JSX.Element => <Icon {...props} icon={HeadphonesSvg} />;
10
+
11
+ Headphones.displayName = 'Headphones';
12
+ export default Headphones;
@@ -0,0 +1,12 @@
1
+ // This icon file is generated automatically.
2
+
3
+ import HeadphonesAiSvg from '../ast/HeadphonesAi';
4
+ import { Icon } from '../Icon';
5
+ import { IconBaseProps } from '../types';
6
+
7
+ const HeadphonesAi = (
8
+ props: IconBaseProps,
9
+ ): JSX.Element => <Icon {...props} icon={HeadphonesAiSvg} />;
10
+
11
+ HeadphonesAi.displayName = 'HeadphonesAi';
12
+ export default HeadphonesAi;
@@ -41,6 +41,8 @@ export { default as BellRinging } from './BellRinging';
41
41
  export { default as BellX } from './BellX';
42
42
  export { default as Bolt } from './Bolt';
43
43
  export { default as Cards } from './Cards';
44
+ export { default as ChatAi } from './ChatAi';
45
+ export { default as Chat } from './Chat';
44
46
  export { default as CheckCircle } from './CheckCircle';
45
47
  export { default as Checked } from './Checked';
46
48
  export { default as ClearValue } from './ClearValue';
@@ -91,6 +93,8 @@ export { default as GlobeSimple } from './GlobeSimple';
91
93
  export { default as Globe } from './Globe';
92
94
  export { default as GoogleDrive } from './GoogleDrive';
93
95
  export { default as GoogleMap } from './GoogleMap';
96
+ export { default as HeadphonesAi } from './HeadphonesAi';
97
+ export { default as Headphones } from './Headphones';
94
98
  export { default as Hide } from './Hide';
95
99
  export { default as Hint } from './Hint';
96
100
  export { default as Home } from './Home';
@@ -22,7 +22,7 @@ export const IntegrationCompactInfoButton: React.FC<{
22
22
  name: string;
23
23
  icon: React.ReactNode;
24
24
  title?: React.ReactNode;
25
- error?: Error;
25
+ error?: Error | null;
26
26
  loading?: boolean;
27
27
  onClick?: () => void;
28
28
  }> = ({onClick, loading, icon, name, title, error}) => {
@@ -0,0 +1,228 @@
1
+ import {ForwardedRef, forwardRef, HTMLAttributes, PropsWithChildren, ReactNode} from "react";
2
+ import {border, space, textStyles, themeVars} from "../design-system";
3
+ import {css, cx} from "@linaria/core";
4
+
5
+ export interface ListRowProps extends HTMLAttributes<HTMLDivElement> {
6
+ darker?: boolean;
7
+ className?: string;
8
+ selected?: boolean;
9
+ done?: boolean;
10
+ focused?: boolean;
11
+ hovered?: boolean;
12
+ }
13
+ export const NATUAL_HOVER_CLASS = "natural-hover";
14
+ export const NATUAL_FOCUS_CLASS = "natural-focus";
15
+ const NATURAL_HOVER = `&.${NATUAL_HOVER_CLASS}:hover`;
16
+ const NATURAL_FOCUS = `&.${NATUAL_FOCUS_CLASS}:focus`;
17
+
18
+ export const listRowSurfaceStylesBase = css`
19
+ max-width: 100%;
20
+ flex-basis: 100%;
21
+ display: flex;
22
+ cursor: default;
23
+ align-items: center;
24
+ align-content: center;
25
+ padding: 0 ${space.s4}px;
26
+ column-gap: ${space.s4}px;
27
+ ${{...textStyles.regular}};
28
+ color: ${themeVars.textColor};
29
+ border-radius: ${border.radius6}px;
30
+ transition: background-color;
31
+
32
+ &:focus {
33
+ outline: none;
34
+ }
35
+
36
+ ${NATURAL_HOVER},
37
+ &.hover {
38
+ cursor: pointer;
39
+ }
40
+
41
+ &.done {
42
+ cursor: not-allowed;
43
+ color: ${themeVars.colorTextListItemGeneralDisabled};
44
+
45
+ > * {
46
+ opacity: ${themeVars.opacityListItemGeneralDisabled};
47
+ }
48
+ }
49
+
50
+ &.selected {
51
+ cursor: default;
52
+ }
53
+ `;
54
+ /* Use it on white background like select option and etc */
55
+ export const listRowSurfaceStatesDefault = css`
56
+ background-color: ${themeVars.colorBgListItemGeneral};
57
+ ${NATURAL_HOVER},
58
+ &.hover {
59
+ cursor: pointer;
60
+ background-color: ${themeVars.colorBgListItemGeneralHover};
61
+ }
62
+
63
+ ${NATURAL_FOCUS}, &.focus {
64
+ background-color: ${themeVars.colorBgListItemGeneralFocus};
65
+ ${NATURAL_HOVER},
66
+ &.hover {
67
+ background-color: ${themeVars.colorBgListItemGeneralFocus};
68
+ }
69
+ }
70
+ &.done {
71
+ cursor: not-allowed;
72
+ color: ${themeVars.colorTextListItemGeneralDisabled};
73
+ background-color: ${themeVars.colorBgListItemGeneralDisabled};
74
+ ${NATURAL_HOVER},
75
+ &.hover,
76
+ ${NATURAL_FOCUS},
77
+ &.focus {
78
+ background-color: ${themeVars.colorBgListItemGeneralDisabled};
79
+ }
80
+ > * {
81
+ opacity: ${themeVars.opacityListItemGeneralDisabled};
82
+ }
83
+ }
84
+ &.selected {
85
+ cursor: default;
86
+ background-color: ${themeVars.colorBgListItemGeneralSelected};
87
+ ${NATURAL_HOVER},
88
+ &.hover {
89
+ background-color: ${themeVars.colorBgListItemGeneralSelectedHover};
90
+ }
91
+ ${NATURAL_FOCUS},
92
+ &.focus {
93
+ background-color: ${themeVars.colorBgListItemGeneralSelectedFocus};
94
+ }
95
+ }
96
+ `;
97
+ /* Use it on dimmed background like left menu or automations list */
98
+ export const listRowSurfaceStatesDark = css`
99
+ background-color: ${themeVars.colorBgMenuItem};
100
+ ${NATURAL_HOVER},
101
+ &.hover {
102
+ cursor: pointer;
103
+ background-color: ${themeVars.colorBgMenuItemHover};
104
+ }
105
+
106
+ ${NATURAL_FOCUS}, &.focus {
107
+ background-color: ${themeVars.colorBgMenuItemFocus};
108
+ ${NATURAL_HOVER},
109
+ &.hover {
110
+ background-color: ${themeVars.colorBgMenuItemFocus};
111
+ }
112
+ }
113
+ &.done {
114
+ cursor: not-allowed;
115
+ color: ${themeVars.colorTextListItemGeneralDisabled};
116
+ background-color: ${themeVars.colorBgListItemGeneralDisabled};
117
+ ${NATURAL_HOVER},
118
+ &.hover,
119
+ ${NATURAL_FOCUS},
120
+ &.focus {
121
+ background-color: ${themeVars.colorBgListItemGeneralDisabled};
122
+ }
123
+ > * {
124
+ opacity: ${themeVars.opacityListItemGeneralDisabled};
125
+ }
126
+ }
127
+ &.selected {
128
+ cursor: default;
129
+ background-color: ${themeVars.colorBgMenuItemSelected};
130
+ ${NATURAL_HOVER},
131
+ &.hover {
132
+ background-color: ${themeVars.colorBgMenuItemSelectedHover};
133
+ cursor: default;
134
+ }
135
+ ${NATURAL_FOCUS},
136
+ &.focus {
137
+ background-color: ${themeVars.colorBgMenuItemSelectedFocused};
138
+ }
139
+ }
140
+ `;
141
+
142
+ /**
143
+ * This should be responsible for all flat list items existing in UI in Fibery. Options, action menus and etc.
144
+ * You can enforce it's state with props focused, hovered, selected, done (use it for disabled too)
145
+ */
146
+
147
+ export const ListRowSurface = forwardRef<HTMLDivElement, ListRowProps>(
148
+ ({selected, focused, darker, hovered, done, className, children, ...rest}, ref) => {
149
+ return (
150
+ <div
151
+ {...rest}
152
+ className={cx(
153
+ listRowSurfaceStylesBase,
154
+ darker ? listRowSurfaceStatesDark : listRowSurfaceStatesDefault,
155
+ className,
156
+ hovered === undefined && NATUAL_HOVER_CLASS,
157
+ focused === undefined && NATUAL_FOCUS_CLASS,
158
+ focused && "focus",
159
+ hovered && "hover",
160
+ selected && "selected",
161
+ done && "done"
162
+ )}
163
+ ref={ref}
164
+ >
165
+ {children}
166
+ </div>
167
+ );
168
+ }
169
+ );
170
+
171
+ export interface ListRowContentProps extends PropsWithChildren<HTMLAttributes<HTMLDivElement>> {
172
+ rootClassName?: string;
173
+ before?: ReactNode;
174
+ after?: ReactNode;
175
+ contentRef?: ForwardedRef<HTMLDivElement>;
176
+ contentClassName?: string;
177
+ beforeClassName?: string;
178
+ afterClassName?: string;
179
+ }
180
+
181
+ const ListRowContentRoot = css`
182
+ flex-basis: 100%;
183
+ display: flex;
184
+ justify-content: stretch;
185
+ align-items: center;
186
+ overflow: hidden;
187
+ gap: ${space.s4}px;
188
+ `;
189
+ const ListRowLayoutSegment = css`
190
+ display: flex; // never new line
191
+ align-items: center;
192
+ `;
193
+ const ListRowContentSegment = css`
194
+ ${{...textStyles.regular}}
195
+ overflow: hidden;
196
+ text-overflow: ellipsis;
197
+ white-space: nowrap;
198
+ min-width: 0; // allows ellipsis in flex contexts :)
199
+ max-width: 100%;
200
+ width: 100%;
201
+ `;
202
+ export const ListRowContent = forwardRef<HTMLDivElement, ListRowContentProps>(
203
+ (
204
+ {
205
+ before,
206
+ after,
207
+ className,
208
+ contentRef,
209
+ rootClassName,
210
+ afterClassName,
211
+ beforeClassName,
212
+ contentClassName,
213
+ children,
214
+ ...rest
215
+ },
216
+ ref
217
+ ) => {
218
+ return (
219
+ <div {...rest} ref={ref} className={cx(ListRowContentRoot, rootClassName, className)}>
220
+ {before ? <div className={cx(ListRowLayoutSegment, beforeClassName)}>{before}</div> : null}
221
+ <div ref={contentRef} className={cx(ListRowContentSegment, contentClassName)}>
222
+ {children}
223
+ </div>
224
+ {after ? <div className={cx(ListRowLayoutSegment, afterClassName)}>{after}</div> : null}
225
+ </div>
226
+ );
227
+ }
228
+ );
@@ -3,10 +3,10 @@ import {components} from "react-windowed-select";
3
3
  import {GroupBase} from "../index";
4
4
  import {css} from "@linaria/core";
5
5
  import {layout, space} from "../../design-system";
6
- import {ListItem} from "../../lists/list-item";
6
+ import {ListRowContent, ListRowSurface} from "../../lists/list-row-surface";
7
7
  import cn from "classnames";
8
- import {Children, ReactNode, useCallback, useMemo, useRef, useState} from "react";
9
- import {Tooltip} from "antd";
8
+ import {Children, ReactNode, useMemo} from "react";
9
+ import {TooltipIfOverflown} from "../../tooltip-if-overflown";
10
10
 
11
11
  export const OptionNulledVitualizedStyles = {
12
12
  height: layout.menuItemHeight,
@@ -30,56 +30,12 @@ const OptionRootClass = css`
30
30
  cursor: pointer;
31
31
  max-width: 100%;
32
32
  `;
33
-
34
- const optionWithTextContent = css`
35
- max-width: 100%;
36
- padding: 0 ${space.s4}px;
37
- `;
38
-
39
- const optionTextOverflowWrapper = css`
40
- max-width: 100%;
41
- flex-basis: 100%;
42
- overflow: hidden;
43
- text-overflow: ellipsis;
44
- white-space: nowrap;
45
- padding: 0 ${space.s4}px;
33
+ const OptionWithTextContent = css`
34
+ padding-left: 0 ${space.s6}px;
46
35
  `;
47
-
48
36
  function isOptionContentIsPureText(children: ReactNode) {
49
37
  return !Children.toArray(children).find((child) => !(typeof child === "string" || typeof child === "number"));
50
38
  }
51
-
52
- type OptionTextContentWithTooltipProps = {
53
- children: string | number;
54
- isFocused?: boolean;
55
- };
56
-
57
- function OptionTextContentWithTooltip({children, isFocused}: OptionTextContentWithTooltipProps) {
58
- const [isTooltipActive, setTooltipActive] = useState<boolean>(false);
59
- const textWrapperRef = useRef<HTMLDivElement>(null);
60
- const textContentRef = useRef<HTMLSpanElement>(null);
61
- const onOptionMouseEnter = useCallback(() => {
62
- setTimeout(() => {
63
- if (!textContentRef.current || !textWrapperRef.current) {
64
- return;
65
- }
66
- isFocused && setTooltipActive(textContentRef.current?.offsetWidth > textWrapperRef.current?.offsetWidth);
67
- }, 300);
68
- }, [textContentRef, textWrapperRef, isFocused]);
69
- return (
70
- <div
71
- className={optionWithTextContent}
72
- onMouseEnter={onOptionMouseEnter}
73
- onMouseLeave={() => setTooltipActive(false)}
74
- >
75
- <Tooltip title={children} mouseEnterDelay={300} placement={"right"} open={isTooltipActive}>
76
- <div ref={textWrapperRef} className={optionTextOverflowWrapper}>
77
- <span ref={textContentRef}>{children}</span>
78
- </div>
79
- </Tooltip>
80
- </div>
81
- );
82
- }
83
39
  /**
84
40
  * Attention! Do not use this option for potentially long lists inside React Select
85
41
  * Why is this option slow? Read here https://the.fibery.io/SoftDev/bug/Select-option-behaviour-is-incorrect-9413
@@ -93,13 +49,33 @@ export function OptionSlow<
93
49
  const isPureText = useMemo(() => isOptionContentIsPureText(children), [children]);
94
50
  return (
95
51
  <components.Option {...rest} className={cn(rest.className, OptionRootClass)}>
96
- <ListItem focused={isFocused} selected={isSelected} hovered={false} done={isDisabled}>
97
- {isPureText ? (
98
- <OptionTextContentWithTooltip isFocused={isFocused}>{children as string}</OptionTextContentWithTooltip>
99
- ) : (
100
- children
101
- )}
102
- </ListItem>
52
+ {isPureText ? (
53
+ <ListRowSurface
54
+ focused={isFocused}
55
+ selected={isSelected}
56
+ hovered={rest.innerProps.onMouseOver ? undefined : false} //if onMouseOver is not passed (fast option used) then enabling natural hover by passing undefined so we not forcing non-hover state
57
+ done={isDisabled}
58
+ >
59
+ <TooltipIfOverflown title={children} side={"right"} sideOffset={space.s6} visible={isFocused}>
60
+ {({setNode}) => {
61
+ return (
62
+ <ListRowContent contentRef={setNode} contentClassName={OptionWithTextContent}>
63
+ {children}
64
+ </ListRowContent>
65
+ );
66
+ }}
67
+ </TooltipIfOverflown>
68
+ </ListRowSurface>
69
+ ) : (
70
+ <ListRowSurface
71
+ focused={isFocused}
72
+ selected={isSelected}
73
+ hovered={rest.innerProps.onMouseOver ? undefined : false} //if onMouseOver is not passed (fast option used) then enabling natural hover by passing undefined so we not forcing non-hover state
74
+ done={isDisabled}
75
+ >
76
+ <ListRowContent>{children}</ListRowContent>
77
+ </ListRowSurface>
78
+ )}
103
79
  </components.Option>
104
80
  );
105
81
  }
@@ -113,7 +89,8 @@ export function Option<Option, IsMulti extends boolean = false, Group extends Gr
113
89
  ...rest
114
90
  }: OptionProps<Option, IsMulti, Group>) {
115
91
  /**
116
- * This makes this option component fast
92
+ * This makes this option component fast.
93
+ * Excluding onMouseOver, onMouseMove makes ReactSelect not rerender the whole list on option hover
117
94
  */
118
95
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
119
96
  const {onMouseOver, onMouseMove, ...truncatedInnerProps} = rest.innerProps;
@@ -103,6 +103,11 @@ function countOptions<Option, Group extends GroupBase<Option>>(categorizedOption
103
103
  }, 0);
104
104
  }
105
105
 
106
+ /**
107
+ * Draws a select input.
108
+ * Please use formatOptionLabel instead of Option component override. Select has smart optimisations for large lists
109
+ * those would be lost and your select slow if options are too numerous
110
+ */
106
111
  export const Select = forwardRef(function Select<
107
112
  Option = unknown,
108
113
  IsMulti extends boolean = boolean,
@@ -0,0 +1,26 @@
1
+ import {useResizeObserver} from "@fibery/react/src/use-resize-observer";
2
+ import {useState} from "react";
3
+ import {Tooltip, TooltipProps} from "./tooltip";
4
+
5
+ type SetNode = (element: HTMLElement | null) => void;
6
+
7
+ export const TooltipIfOverflown: React.FC<
8
+ Omit<TooltipProps, "children"> & {children: (args: {setNode: SetNode}) => JSX.Element | null}
9
+ > = ({children, ...tooltipProps}) => {
10
+ const [truncated, setTruncated] = useState(false);
11
+ const [node, setNode] = useState<HTMLElement | null>(null);
12
+
13
+ useResizeObserver(node, (entry) => {
14
+ const target = entry.target;
15
+ const hasLineClamp = getComputedStyle(target).webkitLineClamp !== "none";
16
+ const truncated = hasLineClamp
17
+ ? target.scrollHeight > target.clientHeight
18
+ : target.scrollWidth > target.clientWidth;
19
+ setTruncated(truncated);
20
+ });
21
+ return (
22
+ <Tooltip {...tooltipProps} disabled={!truncated}>
23
+ {children({setNode})}
24
+ </Tooltip>
25
+ );
26
+ };
@@ -1,8 +0,0 @@
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()});
@@ -1,29 +0,0 @@
1
- import {makeEmojiData} from "@fibery/emoji-data";
2
- import {Suspense, lazy} from "react";
3
- import {EmojiDataStoreProvider} from "./emoji-data-store";
4
- import {getEmojiSet} from "../utils/emoji-set";
5
- import {loadEmojiData} from "../utils/load-emoji-data";
6
-
7
- const LazyEmojiDataStoreComponent = lazy(async () => {
8
- const rawData = await loadEmojiData();
9
-
10
- const emojiData = makeEmojiData(rawData, {set: getEmojiSet()});
11
-
12
- return {
13
- default: function EmojiDataStore({children}: React.PropsWithChildren) {
14
- return <EmojiDataStoreProvider data={emojiData}>{children}</EmojiDataStoreProvider>;
15
- },
16
- };
17
- });
18
-
19
- export const LazyEmojiDataStore: React.FC<
20
- React.PropsWithChildren<{
21
- fallback: React.ReactNode;
22
- }>
23
- > = ({fallback, children}) => {
24
- return (
25
- <Suspense fallback={fallback}>
26
- <LazyEmojiDataStoreComponent>{children}</LazyEmojiDataStoreComponent>
27
- </Suspense>
28
- );
29
- };
@@ -1,139 +0,0 @@
1
- import {styled} from "@linaria/react";
2
- import {forwardRef, HTMLAttributes, PropsWithChildren, ReactNode} from "react";
3
- import {border, space, textStyles, themeVars} from "../design-system";
4
- import {css, cx} from "@linaria/core";
5
-
6
- export interface ListItemGeneralProps extends HTMLAttributes<HTMLDivElement> {
7
- className?: string;
8
- selected?: boolean;
9
- done?: boolean;
10
- focused?: boolean;
11
- hovered?: boolean;
12
- }
13
- const NATUAL_HOVER_CLASS = "natural-hover";
14
- const NATUAL_FOCUS_CLASS = "natural-focus";
15
- const NATURAL_HOVER = `&.${NATUAL_HOVER_CLASS}:hover`;
16
- const NATURAL_FOCUS = `&.${NATUAL_FOCUS_CLASS}:focus`;
17
-
18
- const ListItemGeneralRoot = styled.div`
19
- max-width: 100%;
20
- flex-basis: 100%;
21
- display: flex;
22
- cursor: default;
23
- align-items: center;
24
- align-content: center;
25
- padding: 0 ${space.s4}px;
26
- column-gap: ${space.s4}px;
27
- ${{...textStyles.regular}};
28
- color: ${themeVars.textColor};
29
- border-radius: ${border.radius6}px;
30
- background-color: ${themeVars.colorBgListItemGeneral};
31
- transition: background-color;
32
- ${NATURAL_HOVER},
33
- &.hover {
34
- cursor: pointer;
35
- background-color: ${themeVars.colorBgListItemGeneralHover};
36
- }
37
-
38
- ${NATURAL_FOCUS}, &.focus {
39
- background-color: ${themeVars.colorBgListItemGeneralFocus};
40
- ${NATURAL_HOVER},
41
- &.hover {
42
- background-color: ${themeVars.colorBgListItemGeneralFocus};
43
- }
44
- }
45
- &.done {
46
- cursor: not-allowed;
47
- color: ${themeVars.colorTextListItemGeneralDisabled};
48
- background-color: ${themeVars.colorBgListItemGeneralDisabled};
49
- ${NATURAL_HOVER},
50
- &.hover,
51
- ${NATURAL_FOCUS},
52
- &.focus {
53
- background-color: ${themeVars.colorBgListItemGeneralDisabled};
54
- }
55
- > * {
56
- opacity: ${themeVars.opacityListItemGeneralDisabled};
57
- }
58
- }
59
- &.selected {
60
- cursor: default;
61
- background-color: ${themeVars.colorBgListItemGeneralSelected};
62
- ${NATURAL_HOVER},
63
- &.hover {
64
- background-color: ${themeVars.colorBgListItemGeneralSelectedHover};
65
- }
66
- ${NATURAL_FOCUS},
67
- &.focus {
68
- background-color: ${themeVars.colorBgListItemGeneralSelectedFocus};
69
- }
70
- }
71
- `;
72
-
73
- /**
74
- * This should be responsible for all flat list items existing in UI in Fibery. Options, action menus and etc.
75
- * You can enforce it's state with props focused, hovered, selected, done (use it for disabled too)
76
- */
77
- export const ListItem = forwardRef<HTMLDivElement, ListItemGeneralProps>(
78
- ({selected, focused, hovered, done, className, children, ...rest}, ref) => {
79
- return (
80
- <ListItemGeneralRoot
81
- {...rest}
82
- className={cx(
83
- className,
84
- hovered === undefined && NATUAL_HOVER_CLASS,
85
- focused === undefined && NATUAL_FOCUS_CLASS,
86
- focused && "focus",
87
- hovered && "hover",
88
- selected && "selected",
89
- done && "done"
90
- )}
91
- ref={ref}
92
- >
93
- {children}
94
- </ListItemGeneralRoot>
95
- );
96
- }
97
- );
98
-
99
- export interface ListItemCompoundLayoutProps extends PropsWithChildren<HTMLAttributes<HTMLDivElement>> {
100
- className?: string;
101
- before?: ReactNode;
102
- after?: ReactNode;
103
- contentClassName?: string;
104
- beforeClassName?: string;
105
- afterClassName?: string;
106
- }
107
-
108
- const ListItemCompoundLayoutRoot = css`
109
- flex-basis: 100%;
110
- display: flex;
111
- justify-content: stretch;
112
- align-items: center;
113
- overflow: hidden;
114
- `;
115
- const ListItemCompoundLayoutContainerStyle = css`
116
- display: flex; // never new line
117
- align-items: center;
118
- `;
119
- const ListItemCompoundLayoutContentStyle = css`
120
- ${{...textStyles.regular}}
121
- overflow: hidden;
122
- text-overflow: ellipsis;
123
- padding: 0 0 0 ${space.s4}px;
124
- white-space: nowrap;
125
- min-width: 0; // allows ellipsis in flex contexts :)
126
- max-width: 100%;
127
- width: 100%;
128
- `;
129
- export const ListItemLayout = forwardRef<HTMLDivElement, ListItemCompoundLayoutProps>(
130
- ({before, after, className, afterClassName, beforeClassName, contentClassName, children, ...rest}, ref) => {
131
- return (
132
- <div {...rest} ref={ref} className={cx(className, ListItemCompoundLayoutRoot)}>
133
- {before ? <div className={cx(ListItemCompoundLayoutContainerStyle, beforeClassName)}>{before}</div> : null}
134
- <div className={cx(ListItemCompoundLayoutContentStyle, contentClassName)}>{children}</div>
135
- {after ? <div className={cx(ListItemCompoundLayoutContainerStyle, afterClassName)}>{after}</div> : null}
136
- </div>
137
- );
138
- }
139
- );