@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 +23 -5
- package/src/design-system.ts +13 -0
- package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
- package/src/emoji-picker/primitives/category.tsx +1 -1
- package/src/emoji-picker/primitives/emoji.tsx +1 -1
- package/src/emoji-picker/primitives/grid.tsx +2 -0
- package/src/emoji-picker/primitives/header.tsx +1 -1
- package/src/emoji-picker/stores/emoji-data-store.tsx +13 -10
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +4 -2
- package/src/emoji-picker/stores/static-emoji-data-store.tsx +11 -6
- package/src/icons/ast/Chat.ts +8 -0
- package/src/icons/ast/ChatAi.ts +8 -0
- package/src/icons/ast/Headphones.ts +8 -0
- package/src/icons/ast/HeadphonesAi.ts +8 -0
- package/src/icons/ast/index.tsx +4 -0
- package/src/icons/react/Chat.tsx +12 -0
- package/src/icons/react/ChatAi.tsx +12 -0
- package/src/icons/react/Headphones.tsx +12 -0
- package/src/icons/react/HeadphonesAi.tsx +12 -0
- package/src/icons/react/index.tsx +4 -0
- package/src/integration-compact-info-button.tsx +1 -1
- package/src/lists/list-row-surface.tsx +228 -0
- package/src/select/custom-select-partials/option.tsx +34 -57
- package/src/select/index.tsx +5 -0
- package/src/tooltip-if-overflown.tsx +26 -0
- package/src/emoji-picker/emoji-index.ts +0 -8
- package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +0 -29
- package/src/lists/list-item.tsx +0 -139
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "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.
|
|
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/
|
|
107
|
-
"@fibery/
|
|
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)$":
|
|
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"
|
package/src/design-system.ts
CHANGED
|
@@ -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
|
|
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: "
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/src/icons/ast/index.tsx
CHANGED
|
@@ -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 {
|
|
6
|
+
import {ListRowContent, ListRowSurface} from "../../lists/list-row-surface";
|
|
7
7
|
import cn from "classnames";
|
|
8
|
-
import {Children, ReactNode,
|
|
9
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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;
|
package/src/select/index.tsx
CHANGED
|
@@ -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
|
-
};
|
package/src/lists/list-item.tsx
DELETED
|
@@ -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
|
-
);
|