@fibery/ui-kit 1.21.0 → 1.22.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 +24 -6
- package/src/design-system.ts +12 -0
- package/src/emoji-picker/primitives/emoji.tsx +1 -1
- package/src/emoji-picker/primitives/header.tsx +1 -1
- 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 +2 -2
- package/src/lists/list-row-surface.tsx +220 -0
- package/src/select/custom-select-partials/option.tsx +34 -57
- package/src/tooltip-if-overflown.tsx +26 -0
- package/src/emoji-picker/emoji-index.ts +0 -8
- 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.22.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,9 +69,9 @@
|
|
|
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
72
|
"@fibery/react": "1.3.0",
|
|
73
|
-
"@fibery/helpers": "1.2.0"
|
|
73
|
+
"@fibery/helpers": "1.2.0",
|
|
74
|
+
"@fibery/emoji-data": "2.2.1"
|
|
74
75
|
},
|
|
75
76
|
"peerDependencies": {
|
|
76
77
|
"react": "^18.2.0",
|
|
@@ -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;
|
|
@@ -786,6 +797,7 @@ export const border = {
|
|
|
786
797
|
export const lineHeight = {
|
|
787
798
|
text: 1.6,
|
|
788
799
|
regular: 1.5,
|
|
800
|
+
narrow: 1.4,
|
|
789
801
|
heading: 1.25,
|
|
790
802
|
nowrap: 1,
|
|
791
803
|
} as const;
|
|
@@ -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
|
`;
|
|
@@ -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}) => {
|
|
@@ -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}) => {
|
|
@@ -39,7 +39,7 @@ export const IntegrationCompactInfoButton: React.FC<{
|
|
|
39
39
|
const className = cx(buttonCss, loading && loadingCss);
|
|
40
40
|
|
|
41
41
|
const button = onClick ? (
|
|
42
|
-
<ButtonBase dangerous={Boolean(error)} borderless className={className}>
|
|
42
|
+
<ButtonBase dangerous={Boolean(error)} borderless className={className} onClick={onClick}>
|
|
43
43
|
{iconNode}
|
|
44
44
|
{name}
|
|
45
45
|
</ButtonBase>
|
|
@@ -0,0 +1,220 @@
|
|
|
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
|
+
${NATURAL_HOVER},
|
|
32
|
+
&.hover {
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
}
|
|
35
|
+
&.done {
|
|
36
|
+
cursor: not-allowed;
|
|
37
|
+
color: ${themeVars.colorTextListItemGeneralDisabled};
|
|
38
|
+
> * {
|
|
39
|
+
opacity: ${themeVars.opacityListItemGeneralDisabled};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
&.selected {
|
|
43
|
+
cursor: default;
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
/* Use it on white background like select option and etc */
|
|
47
|
+
export const listRowSurfaceStatesDefault = css`
|
|
48
|
+
background-color: ${themeVars.colorBgListItemGeneral};
|
|
49
|
+
${NATURAL_HOVER},
|
|
50
|
+
&.hover {
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
background-color: ${themeVars.colorBgListItemGeneralHover};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${NATURAL_FOCUS}, &.focus {
|
|
56
|
+
background-color: ${themeVars.colorBgListItemGeneralFocus};
|
|
57
|
+
${NATURAL_HOVER},
|
|
58
|
+
&.hover {
|
|
59
|
+
background-color: ${themeVars.colorBgListItemGeneralFocus};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
&.done {
|
|
63
|
+
cursor: not-allowed;
|
|
64
|
+
color: ${themeVars.colorTextListItemGeneralDisabled};
|
|
65
|
+
background-color: ${themeVars.colorBgListItemGeneralDisabled};
|
|
66
|
+
${NATURAL_HOVER},
|
|
67
|
+
&.hover,
|
|
68
|
+
${NATURAL_FOCUS},
|
|
69
|
+
&.focus {
|
|
70
|
+
background-color: ${themeVars.colorBgListItemGeneralDisabled};
|
|
71
|
+
}
|
|
72
|
+
> * {
|
|
73
|
+
opacity: ${themeVars.opacityListItemGeneralDisabled};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
&.selected {
|
|
77
|
+
cursor: default;
|
|
78
|
+
background-color: ${themeVars.colorBgListItemGeneralSelected};
|
|
79
|
+
${NATURAL_HOVER},
|
|
80
|
+
&.hover {
|
|
81
|
+
background-color: ${themeVars.colorBgListItemGeneralSelectedHover};
|
|
82
|
+
}
|
|
83
|
+
${NATURAL_FOCUS},
|
|
84
|
+
&.focus {
|
|
85
|
+
background-color: ${themeVars.colorBgListItemGeneralSelectedFocus};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
`;
|
|
89
|
+
/* Use it on dimmed background like left menu or automations list */
|
|
90
|
+
export const listRowSurfaceStatesDark = css`
|
|
91
|
+
background-color: ${themeVars.colorBgMenuItem};
|
|
92
|
+
${NATURAL_HOVER},
|
|
93
|
+
&.hover {
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
background-color: ${themeVars.colorBgMenuItemHover};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
${NATURAL_FOCUS}, &.focus {
|
|
99
|
+
background-color: ${themeVars.colorBgMenuItemFocus};
|
|
100
|
+
${NATURAL_HOVER},
|
|
101
|
+
&.hover {
|
|
102
|
+
background-color: ${themeVars.colorBgMenuItemFocus};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
&.done {
|
|
106
|
+
cursor: not-allowed;
|
|
107
|
+
color: ${themeVars.colorTextListItemGeneralDisabled};
|
|
108
|
+
background-color: ${themeVars.colorBgListItemGeneralDisabled};
|
|
109
|
+
${NATURAL_HOVER},
|
|
110
|
+
&.hover,
|
|
111
|
+
${NATURAL_FOCUS},
|
|
112
|
+
&.focus {
|
|
113
|
+
background-color: ${themeVars.colorBgListItemGeneralDisabled};
|
|
114
|
+
}
|
|
115
|
+
> * {
|
|
116
|
+
opacity: ${themeVars.opacityListItemGeneralDisabled};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
&.selected {
|
|
120
|
+
cursor: default;
|
|
121
|
+
background-color: ${themeVars.colorBgMenuItemSelected};
|
|
122
|
+
${NATURAL_HOVER},
|
|
123
|
+
&.hover {
|
|
124
|
+
background-color: ${themeVars.colorBgMenuItemSelectedHover};
|
|
125
|
+
cursor: default;
|
|
126
|
+
}
|
|
127
|
+
${NATURAL_FOCUS},
|
|
128
|
+
&.focus {
|
|
129
|
+
background-color: ${themeVars.colorBgMenuItemSelectedFocused};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* This should be responsible for all flat list items existing in UI in Fibery. Options, action menus and etc.
|
|
136
|
+
* You can enforce it's state with props focused, hovered, selected, done (use it for disabled too)
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
export const ListRowSurface = forwardRef<HTMLDivElement, ListRowProps>(
|
|
140
|
+
({selected, focused, darker, hovered, done, className, children, ...rest}, ref) => {
|
|
141
|
+
return (
|
|
142
|
+
<div
|
|
143
|
+
{...rest}
|
|
144
|
+
className={cx(
|
|
145
|
+
listRowSurfaceStylesBase,
|
|
146
|
+
darker ? listRowSurfaceStatesDark : listRowSurfaceStatesDefault,
|
|
147
|
+
className,
|
|
148
|
+
hovered === undefined && NATUAL_HOVER_CLASS,
|
|
149
|
+
focused === undefined && NATUAL_FOCUS_CLASS,
|
|
150
|
+
focused && "focus",
|
|
151
|
+
hovered && "hover",
|
|
152
|
+
selected && "selected",
|
|
153
|
+
done && "done"
|
|
154
|
+
)}
|
|
155
|
+
ref={ref}
|
|
156
|
+
>
|
|
157
|
+
{children}
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
export interface ListRowContentProps extends PropsWithChildren<HTMLAttributes<HTMLDivElement>> {
|
|
164
|
+
rootClassName?: string;
|
|
165
|
+
before?: ReactNode;
|
|
166
|
+
after?: ReactNode;
|
|
167
|
+
contentRef?: ForwardedRef<HTMLDivElement>;
|
|
168
|
+
contentClassName?: string;
|
|
169
|
+
beforeClassName?: string;
|
|
170
|
+
afterClassName?: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const ListRowContentRoot = css`
|
|
174
|
+
flex-basis: 100%;
|
|
175
|
+
display: flex;
|
|
176
|
+
justify-content: stretch;
|
|
177
|
+
align-items: center;
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
gap: ${space.s4}px;
|
|
180
|
+
`;
|
|
181
|
+
const ListRowLayoutSegment = css`
|
|
182
|
+
display: flex; // never new line
|
|
183
|
+
align-items: center;
|
|
184
|
+
`;
|
|
185
|
+
const ListRowContentSegment = css`
|
|
186
|
+
${{...textStyles.regular}}
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
text-overflow: ellipsis;
|
|
189
|
+
white-space: nowrap;
|
|
190
|
+
min-width: 0; // allows ellipsis in flex contexts :)
|
|
191
|
+
max-width: 100%;
|
|
192
|
+
width: 100%;
|
|
193
|
+
`;
|
|
194
|
+
export const ListRowContent = forwardRef<HTMLDivElement, ListRowContentProps>(
|
|
195
|
+
(
|
|
196
|
+
{
|
|
197
|
+
before,
|
|
198
|
+
after,
|
|
199
|
+
className,
|
|
200
|
+
contentRef,
|
|
201
|
+
rootClassName,
|
|
202
|
+
afterClassName,
|
|
203
|
+
beforeClassName,
|
|
204
|
+
contentClassName,
|
|
205
|
+
children,
|
|
206
|
+
...rest
|
|
207
|
+
},
|
|
208
|
+
ref
|
|
209
|
+
) => {
|
|
210
|
+
return (
|
|
211
|
+
<div {...rest} ref={ref} className={cx(ListRowContentRoot, rootClassName, className)}>
|
|
212
|
+
{before ? <div className={cx(ListRowLayoutSegment, beforeClassName)}>{before}</div> : null}
|
|
213
|
+
<div ref={contentRef} className={cx(ListRowContentSegment, contentClassName)}>
|
|
214
|
+
{children}
|
|
215
|
+
</div>
|
|
216
|
+
{after ? <div className={cx(ListRowLayoutSegment, afterClassName)}>{after}</div> : null}
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
);
|
|
@@ -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;
|
|
@@ -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()});
|
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
|
-
);
|