@fibery/ui-kit 1.40.2 → 1.40.4
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/CHANGELOG.md +14 -0
- package/package.json +4 -7
- package/src/__snapshots__/design-system.test.ts.snap +7265 -0
- package/src/a11y-color.test.ts +181 -0
- package/src/a11y-color.ts +13 -20
- package/src/actions-menu/actions-menu-item.tsx +7 -7
- package/src/antd/ant-modal.tsx +10 -5
- package/src/antd/styles.ts +6 -6
- package/src/app-icon-with-fallback.tsx +2 -2
- package/src/app-icon.tsx +2 -2
- package/src/button/button.tsx +1 -0
- package/src/button/make-button-colors.ts +5 -13
- package/src/checkbox.tsx +2 -2
- package/src/color-picker/ColorPickerOrLoader.js +2 -2
- package/src/color-utils.test.ts +317 -0
- package/src/color-utils.ts +180 -0
- package/src/comment.tsx +3 -2
- package/src/context-menu/index.tsx +12 -7
- package/src/create-inline-theme.ts +9 -8
- package/src/design-system.colors.ts +760 -0
- package/src/design-system.test.ts +287 -7
- package/src/design-system.ts +146 -940
- package/src/dropdown-menu/index.tsx +21 -16
- package/src/emoji-picker/app-icon-picker.tsx +5 -5
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +4 -4
- package/src/emoji-picker/icon-emoji-picker.tsx +2 -2
- package/src/favorites-icon.tsx +1 -1
- package/src/file-item/file-icon.tsx +169 -0
- package/src/file-item/file-menu-items.tsx +68 -0
- package/src/file-item/file-preview-actions.tsx +38 -0
- package/src/file-item/file-title.tsx +48 -0
- package/src/file-item/types.ts +27 -0
- package/src/file-item/use-register-in-image-gallery.tsx +70 -0
- package/src/file-item-2.tsx +35 -345
- package/src/file-item.tsx +6 -2
- package/src/hue-shift.test.ts +91 -0
- package/src/icons/Icon.tsx +1 -0
- package/src/icons/ast/FileCounter.ts +8 -0
- package/src/icons/ast/FileMultiple.ts +8 -0
- package/src/icons/ast/Print.ts +8 -0
- package/src/icons/ast/ValueEdit.ts +8 -0
- package/src/icons/ast/index.tsx +4 -0
- package/src/icons/react/Dividers.tsx +1 -1
- package/src/icons/react/FileCounter.tsx +13 -0
- package/src/icons/react/FileMultiple.tsx +13 -0
- package/src/icons/react/Print.tsx +13 -0
- package/src/icons/react/ValueEdit.tsx +13 -0
- package/src/icons/react/index.tsx +4 -0
- package/src/icons/svg/file-counter.svg +3 -0
- package/src/icons/svg/file-multiple.svg +3 -0
- package/src/icons/svg/print.svg +3 -0
- package/src/icons/svg/value-edit.svg +3 -0
- package/src/images-gallery/slide-buttons.tsx +4 -11
- package/src/lists/actions-menu-row-surface.tsx +5 -5
- package/src/mobile-keyboard-aware-popup.tsx +4 -3
- package/src/palette-generator.test.ts +566 -0
- package/src/palette-generator.ts +166 -0
- package/src/palette.ts +71 -55
- package/src/platform.ts +0 -3
- package/src/popover/index.tsx +20 -28
- package/src/progress.tsx +2 -2
- package/src/reactions/reaction-button.tsx +12 -6
- package/src/root-theme-provider.test.tsx +316 -0
- package/src/scale-generator.ts +347 -0
- package/src/select/components/menu-list-virtualized.tsx +7 -22
- package/src/select/components/menu.tsx +12 -2
- package/src/select/select.tsx +2 -1
- package/src/select/styles.ts +0 -1
- package/src/static-palettes.ts +146 -0
- package/src/thematic-color-picker.tsx +266 -0
- package/src/thematic-constants.tsx +27 -0
- package/src/thematic-controls.tsx +144 -0
- package/src/thematic-scales.tsx +122 -0
- package/src/thematic-state.ts +333 -0
- package/src/thematic.tsx +382 -0
- package/src/theme-provider.test.tsx +808 -0
- package/src/theme-provider.tsx +132 -69
- package/src/theme-settings.ts +1 -1
- package/src/theme-styles.ts +12 -5
- package/src/toast/toast-action.tsx +1 -1
- package/src/toggle-on-off.tsx +2 -2
- package/src/toggle.tsx +5 -6
- package/src/tooltip.tsx +13 -10
- package/src/type-badge.tsx +3 -3
- package/src/unit/styles.ts +2 -2
- package/src/unit/unit-with-tooltip.tsx +3 -2
- package/src/use-long-press.tsx +2 -2
|
@@ -5,6 +5,7 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
|
5
5
|
import {forwardRef} from "react";
|
|
6
6
|
import {border, layout, space, textStyles, themeVars} from "../design-system";
|
|
7
7
|
import {mobileRootSelector} from "../mobile-styles";
|
|
8
|
+
import {ThemeProvider} from "../theme-provider";
|
|
8
9
|
|
|
9
10
|
export const Root = (dropdownMenuProps: DropdownMenuPrimitive.DropdownMenuProps) => (
|
|
10
11
|
<DropdownMenuPrimitive.Root dir="ltr" modal={false} {...dropdownMenuProps} />
|
|
@@ -133,16 +134,18 @@ export const Content = forwardRef<HTMLDivElement, ContentProps>(function Dropdow
|
|
|
133
134
|
) {
|
|
134
135
|
return (
|
|
135
136
|
<Wrap if={portalled} with={DropdownMenuPrimitive.Portal} container={container}>
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
<ThemeProvider portal>
|
|
138
|
+
<DropdownMenuPrimitive.Content
|
|
139
|
+
onKeyDown={onContentKeyDown}
|
|
140
|
+
ref={ref}
|
|
141
|
+
className={cx(dropdownMenuContentStyles, className)}
|
|
142
|
+
side="bottom"
|
|
143
|
+
align="start"
|
|
144
|
+
collisionPadding={collisionPadding}
|
|
145
|
+
sideOffset={space.s4}
|
|
146
|
+
{...rest}
|
|
147
|
+
/>
|
|
148
|
+
</ThemeProvider>
|
|
146
149
|
</Wrap>
|
|
147
150
|
);
|
|
148
151
|
});
|
|
@@ -155,12 +158,14 @@ export const SubContent = forwardRef<
|
|
|
155
158
|
>(function DropdownMenuSubContent({className, collisionPadding = space.s12, container, ...rest}, ref) {
|
|
156
159
|
return (
|
|
157
160
|
<DropdownMenuPrimitive.Portal container={container}>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
<ThemeProvider portal>
|
|
162
|
+
<DropdownMenuPrimitive.SubContent
|
|
163
|
+
ref={ref}
|
|
164
|
+
className={cx(dropdownMenuContentStyles, className)}
|
|
165
|
+
collisionPadding={collisionPadding}
|
|
166
|
+
{...rest}
|
|
167
|
+
/>
|
|
168
|
+
</ThemeProvider>
|
|
164
169
|
</DropdownMenuPrimitive.Portal>
|
|
165
170
|
);
|
|
166
171
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {CustomEmoji, EmojiItem} from "@fibery/emoji-data";
|
|
2
2
|
import {useCallback} from "react";
|
|
3
|
-
import {cardTypeColors
|
|
4
|
-
import {
|
|
3
|
+
import {cardTypeColors} from "../design-system";
|
|
4
|
+
import {useTheme} from "../theme-provider";
|
|
5
5
|
import {$TSFixMe} from "../tsfixme";
|
|
6
6
|
import {EmojiPickerContentWithColor, EmojiPickerContentWithColorProps} from "./emoji-picker-content-with-color";
|
|
7
7
|
import {EmojiPickerContent} from "./primitives/content";
|
|
@@ -30,7 +30,7 @@ export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
|
30
30
|
autoFocus = true,
|
|
31
31
|
emojiSize = 20,
|
|
32
32
|
}) => {
|
|
33
|
-
const
|
|
33
|
+
const theme = useTheme();
|
|
34
34
|
|
|
35
35
|
const renderEmoji = useCallback<NonNullable<EmojiPickerContentWithColorProps["renderEmoji"]>>(
|
|
36
36
|
({emoji}) => (
|
|
@@ -39,14 +39,14 @@ export const AppIconPicker: React.FC<AppIconPickerProps> = ({
|
|
|
39
39
|
display: "block",
|
|
40
40
|
width: emojiSize,
|
|
41
41
|
height: emojiSize,
|
|
42
|
-
fill: color ? getIconColor(
|
|
42
|
+
fill: color ? theme.fns.getIconColor(color) : undefined,
|
|
43
43
|
}}
|
|
44
44
|
viewBox="0 0 24 24"
|
|
45
45
|
>
|
|
46
46
|
<use href={(emoji as CustomEmoji).imageUrl} />
|
|
47
47
|
</svg>
|
|
48
48
|
),
|
|
49
|
-
[color,
|
|
49
|
+
[color, theme, emojiSize]
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
return (
|
|
@@ -2,8 +2,8 @@ import {css} from "@linaria/core";
|
|
|
2
2
|
import {useRef, useState} from "react";
|
|
3
3
|
import {CollapsibleContent, CollapsibleRoot, CollapsibleTrigger} from "../collapsible";
|
|
4
4
|
import {ColorPicker} from "../color-picker";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import {space, themeVars} from "../design-system";
|
|
6
|
+
import {useTheme} from "../theme-provider";
|
|
7
7
|
import {Tooltip} from "../tooltip";
|
|
8
8
|
import {$TSFixMe} from "../tsfixme";
|
|
9
9
|
import {EmojiPickerGrid, type EmojiPickerGridHandle, EmojiPickerGridProps} from "./primitives/grid";
|
|
@@ -18,8 +18,8 @@ const colorPickerWrapperCss = css`
|
|
|
18
18
|
type ColorPickerCollapsibleTrigger = {opened: boolean; color?: string};
|
|
19
19
|
|
|
20
20
|
const ColorPickerCollapsibleTrigger: React.FC<ColorPickerCollapsibleTrigger> = ({opened, color}) => {
|
|
21
|
-
const
|
|
22
|
-
const iconColor = color ? getIconColor(
|
|
21
|
+
const theme = useTheme();
|
|
22
|
+
const iconColor = color ? theme.fns.getIconColor(color) : undefined;
|
|
23
23
|
|
|
24
24
|
const label = opened ? "Hide color picker" : "Show color picker";
|
|
25
25
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
2
|
import {compact} from "lodash";
|
|
3
3
|
import {Button} from "../button/button";
|
|
4
|
-
import {
|
|
4
|
+
import {space, themeVars} from "../design-system";
|
|
5
5
|
import EmojiDelete from "../icons/react/EmojiDelete";
|
|
6
6
|
import {$TSFixMe} from "../tsfixme";
|
|
7
7
|
import {AppIconPicker, AppIconPickerProps} from "./app-icon-picker";
|
|
@@ -11,7 +11,7 @@ import {useState} from "react";
|
|
|
11
11
|
|
|
12
12
|
const tabNavRootStyle = css`
|
|
13
13
|
padding: ${space.s4}px ${space.s12}px 0 ${space.s12}px;
|
|
14
|
-
box-shadow: inset 0 -1px ${
|
|
14
|
+
box-shadow: inset 0 -1px ${themeVars.shades.opacity5};
|
|
15
15
|
`;
|
|
16
16
|
|
|
17
17
|
type TabKey = "icons" | "emojis";
|
package/src/favorites-icon.tsx
CHANGED
|
@@ -74,7 +74,7 @@ export const FavoritesIcon = ({
|
|
|
74
74
|
onClick={onClick}
|
|
75
75
|
>
|
|
76
76
|
<IconButton
|
|
77
|
-
style={checked ? makeButtonColors(theme.favoritesIconColor, "ghost") : {}}
|
|
77
|
+
style={checked ? makeButtonColors(theme.favoritesIconColor, "ghost", theme) : {}}
|
|
78
78
|
size={size || "medium"}
|
|
79
79
|
onClick={handleChange}
|
|
80
80
|
color="neutral"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import FileImage from "../icons/react/FileImage";
|
|
2
|
+
import FileVideo from "../icons/react/FileVideo";
|
|
3
|
+
import FileTable from "../icons/react/FileTable";
|
|
4
|
+
import FileDocument from "../icons/react/FileDocument";
|
|
5
|
+
import FileArchive from "../icons/react/FileArchive";
|
|
6
|
+
import FilePresentation from "../icons/react/FilePresentation";
|
|
7
|
+
import AppWiki from "../icons/react/AppWiki";
|
|
8
|
+
|
|
9
|
+
export function getFileIconComponent(contentType?: string) {
|
|
10
|
+
if (!contentType) {
|
|
11
|
+
return AppWiki;
|
|
12
|
+
}
|
|
13
|
+
if (contentType.startsWith("image/")) {
|
|
14
|
+
return FileImage;
|
|
15
|
+
}
|
|
16
|
+
if (contentType.startsWith("video/")) {
|
|
17
|
+
return FileVideo;
|
|
18
|
+
}
|
|
19
|
+
if (SheetsContentTypes.includes(contentType)) {
|
|
20
|
+
return FileTable;
|
|
21
|
+
}
|
|
22
|
+
if (ArchiveContentTypes.includes(contentType)) {
|
|
23
|
+
return FileArchive;
|
|
24
|
+
}
|
|
25
|
+
if (PresentationContentTypes.includes(contentType)) {
|
|
26
|
+
return FilePresentation;
|
|
27
|
+
}
|
|
28
|
+
if (DocumentContentTypes.includes(contentType) || contentType.startsWith("text/")) {
|
|
29
|
+
return FileDocument;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return AppWiki;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function FileIcon({contentType}: {contentType?: string}) {
|
|
36
|
+
const Component = getFileIconComponent(contentType);
|
|
37
|
+
return <Component />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const ArchiveContentTypes = [
|
|
41
|
+
"application/zip",
|
|
42
|
+
"application/zip-compressed",
|
|
43
|
+
"application/x-zip",
|
|
44
|
+
"application/x-zip-compressed",
|
|
45
|
+
"multipart/x-zip",
|
|
46
|
+
|
|
47
|
+
"application/x-rar-compressed",
|
|
48
|
+
"application/vnd.rar",
|
|
49
|
+
|
|
50
|
+
"application/x-7z-compressed",
|
|
51
|
+
|
|
52
|
+
"application/gzip",
|
|
53
|
+
"application/x-gzip",
|
|
54
|
+
|
|
55
|
+
"application/x-tar",
|
|
56
|
+
|
|
57
|
+
"application/x-bzip",
|
|
58
|
+
"application/x-bzip2",
|
|
59
|
+
"application/x-bzip3",
|
|
60
|
+
"application/x-bzip4",
|
|
61
|
+
|
|
62
|
+
"application/x-xz",
|
|
63
|
+
|
|
64
|
+
"application/zstd",
|
|
65
|
+
"application/x-zstd",
|
|
66
|
+
|
|
67
|
+
"application/x-lzma",
|
|
68
|
+
"application/x-lzip",
|
|
69
|
+
|
|
70
|
+
"application/x-lzh",
|
|
71
|
+
"application/x-lha",
|
|
72
|
+
|
|
73
|
+
"application/x-iso9660-image",
|
|
74
|
+
"application/x-cd-image",
|
|
75
|
+
|
|
76
|
+
"application/x-apple-diskimage",
|
|
77
|
+
|
|
78
|
+
"application/x-arj",
|
|
79
|
+
|
|
80
|
+
"application/x-cpio",
|
|
81
|
+
|
|
82
|
+
"application/x-rpm",
|
|
83
|
+
|
|
84
|
+
"application/x-deb",
|
|
85
|
+
"application/vnd.debian.binary-package",
|
|
86
|
+
|
|
87
|
+
"application/x-compress",
|
|
88
|
+
"application/x-archive",
|
|
89
|
+
"application/vnd.android.package-archive",
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const PresentationContentTypes = [
|
|
93
|
+
"application/x-iwork-keynote-sffkey",
|
|
94
|
+
"application/vnd.ms-powerpoint",
|
|
95
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
96
|
+
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
|
97
|
+
"application/vnd.openxmlformats-officedocument.presentationml.template",
|
|
98
|
+
"application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
|
99
|
+
"application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
|
100
|
+
"application/vnd.ms-powerpoint.template.macroEnabled.12",
|
|
101
|
+
"application/vnd.oasis.opendocument.presentation",
|
|
102
|
+
"application/vnd.oasis.opendocument.presentation-template",
|
|
103
|
+
"application/vnd.apple.keynote",
|
|
104
|
+
"application/vnd.google-apps.presentation",
|
|
105
|
+
"application/pdf",
|
|
106
|
+
"application/vnd.sun.xml.impress",
|
|
107
|
+
"application/vnd.stardivision.impress",
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const SheetsContentTypes = [
|
|
111
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
112
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
|
113
|
+
"application/vnd.ms-excel",
|
|
114
|
+
"application/vnd.ms-excel.sheet.macroEnabled.12",
|
|
115
|
+
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
116
|
+
"application/vnd.ms-excel.addin.macroEnabled.12",
|
|
117
|
+
"application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
|
118
|
+
"application/vnd.oasis.opendocument.spreadsheet",
|
|
119
|
+
"application/vnd.oasis.opendocument.spreadsheet-template",
|
|
120
|
+
"application/vnd.apple.numbers",
|
|
121
|
+
"application/vnd.google-apps.spreadsheet",
|
|
122
|
+
"text/csv",
|
|
123
|
+
"text/x-comma-separated-values",
|
|
124
|
+
"application/csv",
|
|
125
|
+
"text/tab-separated-values",
|
|
126
|
+
"application/vnd.lotus-1-2-3",
|
|
127
|
+
"application/x-123",
|
|
128
|
+
"application/vnd.stardivision.calc",
|
|
129
|
+
"application/vnd.sun.xml.calc",
|
|
130
|
+
"application/x-dbase",
|
|
131
|
+
"application/x-iwork-numbers-sffnumbers",
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const DocumentContentTypes = [
|
|
135
|
+
"application/msword",
|
|
136
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
137
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
|
138
|
+
"application/vnd.ms-word.document.macroEnabled.12",
|
|
139
|
+
"application/vnd.ms-word.template.macroEnabled.12",
|
|
140
|
+
|
|
141
|
+
"application/vnd.oasis.opendocument.text",
|
|
142
|
+
"application/vnd.oasis.opendocument.text-template",
|
|
143
|
+
"application/vnd.oasis.opendocument.text-master",
|
|
144
|
+
"application/vnd.oasis.opendocument.text-web",
|
|
145
|
+
|
|
146
|
+
"application/vnd.apple.pages",
|
|
147
|
+
"application/x-iwork-pages-sffpages",
|
|
148
|
+
|
|
149
|
+
"application/rtf",
|
|
150
|
+
"text/rtf",
|
|
151
|
+
|
|
152
|
+
"text/plain",
|
|
153
|
+
"text/markdown",
|
|
154
|
+
"text/html",
|
|
155
|
+
|
|
156
|
+
"application/vnd.google-apps.document",
|
|
157
|
+
|
|
158
|
+
"application/vnd.sun.xml.writer",
|
|
159
|
+
"application/vnd.sun.xml.writer.template",
|
|
160
|
+
"application/vnd.sun.xml.writer.global",
|
|
161
|
+
|
|
162
|
+
"application/vnd.stardivision.writer",
|
|
163
|
+
"application/vnd.stardivision.writer-global",
|
|
164
|
+
|
|
165
|
+
"application/x-mswrite",
|
|
166
|
+
"application/x-abiword",
|
|
167
|
+
|
|
168
|
+
"application/pdf",
|
|
169
|
+
];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {ReactNode} from "react";
|
|
2
|
+
import {useToast} from "../toast/toast-provider";
|
|
3
|
+
import {ActionsMenuItem, ActionsMenuSeparator} from "../actions-menu";
|
|
4
|
+
import Link from "../icons/react/Link";
|
|
5
|
+
import {copyUrlToClipboard} from "../copy-to-clipboard";
|
|
6
|
+
import RicheditorOpenLink from "../icons/react/RicheditorOpenLink";
|
|
7
|
+
import {isPhoneApp} from "../use-is-phone";
|
|
8
|
+
import FileDownload from "../icons/react/FileDownload";
|
|
9
|
+
import Pencil from "../icons/react/Pencil";
|
|
10
|
+
import Delete from "../icons/react/Delete";
|
|
11
|
+
import {UploadFileWithContent} from "./types";
|
|
12
|
+
|
|
13
|
+
export function FileMenuItems({
|
|
14
|
+
file,
|
|
15
|
+
disabled,
|
|
16
|
+
onDownloadClick,
|
|
17
|
+
onRemoveClick,
|
|
18
|
+
onRenameClick,
|
|
19
|
+
}: {
|
|
20
|
+
file: Pick<UploadFileWithContent, "uid" | "name" | "url" | "status">;
|
|
21
|
+
onDownloadClick?: () => void;
|
|
22
|
+
onRemoveClick?: () => void;
|
|
23
|
+
onRenameClick?: (data: {id: string; name: string}) => void;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}): ReactNode {
|
|
26
|
+
const toast = useToast();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<ActionsMenuItem
|
|
31
|
+
Icon={Link}
|
|
32
|
+
onSelect={() => {
|
|
33
|
+
copyUrlToClipboard({url: `${window.origin}${file.url}`, label: file.name})
|
|
34
|
+
.then(() => toast.success({title: "Link copied to clipboard"}))
|
|
35
|
+
.catch((error) => toast.error({title: "Unable to copy link to clipboard", subTitle: error.message}));
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
Copy file URL
|
|
39
|
+
</ActionsMenuItem>
|
|
40
|
+
<a href={file.url} target="_blank" rel="noopener noreferrer">
|
|
41
|
+
<ActionsMenuItem Icon={RicheditorOpenLink}>
|
|
42
|
+
{isPhoneApp() ? "Open in browser" : "Open in new tab"}
|
|
43
|
+
</ActionsMenuItem>
|
|
44
|
+
</a>
|
|
45
|
+
{isPhoneApp() ? (
|
|
46
|
+
<ActionsMenuItem Icon={FileDownload} onSelect={onDownloadClick}>
|
|
47
|
+
Download
|
|
48
|
+
</ActionsMenuItem>
|
|
49
|
+
) : (
|
|
50
|
+
<a download={file.name} href={`${file.url}?attachment`}>
|
|
51
|
+
<ActionsMenuItem Icon={FileDownload}>Download</ActionsMenuItem>
|
|
52
|
+
</a>
|
|
53
|
+
)}
|
|
54
|
+
{onRenameClick && file.status === "done" ? (
|
|
55
|
+
<>
|
|
56
|
+
<ActionsMenuSeparator />
|
|
57
|
+
<ActionsMenuItem Icon={Pencil} onSelect={() => onRenameClick?.({id: file.uid, name: file.name})}>
|
|
58
|
+
Rename
|
|
59
|
+
</ActionsMenuItem>
|
|
60
|
+
</>
|
|
61
|
+
) : null}
|
|
62
|
+
<ActionsMenuSeparator />
|
|
63
|
+
<ActionsMenuItem Icon={Delete} onSelect={onRemoveClick} dangerous disabled={disabled}>
|
|
64
|
+
Delete
|
|
65
|
+
</ActionsMenuItem>
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {isPhoneApp} from "../use-is-phone";
|
|
2
|
+
import {ActionsMenuItem} from "../actions-menu";
|
|
3
|
+
import RicheditorOpenLink from "../icons/react/RicheditorOpenLink";
|
|
4
|
+
import FileDownload from "../icons/react/FileDownload";
|
|
5
|
+
|
|
6
|
+
export function FilePreviewActions({
|
|
7
|
+
url,
|
|
8
|
+
name,
|
|
9
|
+
onDownloadClick,
|
|
10
|
+
}: {
|
|
11
|
+
url: string;
|
|
12
|
+
name: string;
|
|
13
|
+
onDownloadClick?: () => void;
|
|
14
|
+
}) {
|
|
15
|
+
if (isPhoneApp()) {
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
<a href={url} target="_blank" rel="noopener noreferrer">
|
|
19
|
+
<ActionsMenuItem Icon={RicheditorOpenLink}>Open in browser</ActionsMenuItem>
|
|
20
|
+
</a>
|
|
21
|
+
<ActionsMenuItem Icon={FileDownload} onSelect={onDownloadClick}>
|
|
22
|
+
Download
|
|
23
|
+
</ActionsMenuItem>
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<a href={url} target="_blank" rel="noopener noreferrer">
|
|
31
|
+
<ActionsMenuItem Icon={RicheditorOpenLink}>Open in new tab</ActionsMenuItem>
|
|
32
|
+
</a>
|
|
33
|
+
<a download={name} href={`${url}?attachment`}>
|
|
34
|
+
<ActionsMenuItem Icon={FileDownload}>Download</ActionsMenuItem>
|
|
35
|
+
</a>
|
|
36
|
+
</>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {css, cx, LinariaClassName} from "@linaria/core";
|
|
2
|
+
|
|
3
|
+
export function FileTitle({
|
|
4
|
+
title,
|
|
5
|
+
containerCss,
|
|
6
|
+
maxWidth,
|
|
7
|
+
}: {
|
|
8
|
+
title: string;
|
|
9
|
+
containerCss?: LinariaClassName;
|
|
10
|
+
maxWidth?: number;
|
|
11
|
+
}) {
|
|
12
|
+
const parts = title.split(".");
|
|
13
|
+
const ext = parts.length > 1 ? "." + parts[parts.length - 1] : "";
|
|
14
|
+
const name = title.substring(0, title.length - ext.length);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className={cx(
|
|
19
|
+
css`
|
|
20
|
+
display: flex;
|
|
21
|
+
min-width: 0;
|
|
22
|
+
align-items: center;
|
|
23
|
+
`,
|
|
24
|
+
containerCss
|
|
25
|
+
)}
|
|
26
|
+
style={{maxWidth}}
|
|
27
|
+
>
|
|
28
|
+
<span
|
|
29
|
+
className={css`
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
text-overflow: ellipsis;
|
|
33
|
+
/* ellipsis shows ONLY if this span overflows */
|
|
34
|
+
min-width: 0;
|
|
35
|
+
`}
|
|
36
|
+
>
|
|
37
|
+
{name}
|
|
38
|
+
</span>
|
|
39
|
+
<span
|
|
40
|
+
className={css`
|
|
41
|
+
flex: 0 0 auto;
|
|
42
|
+
`}
|
|
43
|
+
>
|
|
44
|
+
{ext}
|
|
45
|
+
</span>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type FiberyFile = {
|
|
2
|
+
"fibery/id": string;
|
|
3
|
+
"fibery/name": string;
|
|
4
|
+
"fibery/rank": number;
|
|
5
|
+
"fibery/content-type": string;
|
|
6
|
+
"fibery/secret": string;
|
|
7
|
+
"fibery/content-length": number;
|
|
8
|
+
"fibery/creation-date": string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type PreviewData = {
|
|
12
|
+
type: "image" | "video" | "iframe";
|
|
13
|
+
previewSrc: string | null;
|
|
14
|
+
originalSrc: string;
|
|
15
|
+
contentType: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type UploadFileWithContent = {
|
|
19
|
+
uid: string;
|
|
20
|
+
name: string;
|
|
21
|
+
url: string;
|
|
22
|
+
status?: string;
|
|
23
|
+
contentType: string;
|
|
24
|
+
thumbnailUrl: string | null;
|
|
25
|
+
downloadUrl?: string | null;
|
|
26
|
+
previewData: null | PreviewData;
|
|
27
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {useCallback, useEffect, useState} from "react";
|
|
2
|
+
import {useImagesGalleryMethods, useImagesGalleryRegistry} from "../images-gallery/images-gallery";
|
|
3
|
+
import {FilePreviewActions} from "./file-preview-actions";
|
|
4
|
+
import {PreviewData} from "./types";
|
|
5
|
+
|
|
6
|
+
export function useRegisterInImageGallery({
|
|
7
|
+
preview,
|
|
8
|
+
name,
|
|
9
|
+
onDownloadClick,
|
|
10
|
+
}: {
|
|
11
|
+
preview: PreviewData | null;
|
|
12
|
+
name: string;
|
|
13
|
+
onDownloadClick?: () => void;
|
|
14
|
+
}) {
|
|
15
|
+
const [zoomed, setZoomed] = useState(false);
|
|
16
|
+
const imagesRegistry = useImagesGalleryRegistry();
|
|
17
|
+
const galleryMethods = useImagesGalleryMethods();
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!preview) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
imagesRegistry.set(preview.originalSrc, {
|
|
25
|
+
type: preview.type,
|
|
26
|
+
src: preview.originalSrc,
|
|
27
|
+
label: name,
|
|
28
|
+
zoomed: false,
|
|
29
|
+
setZoomed,
|
|
30
|
+
actions: <FilePreviewActions url={preview.originalSrc} name={name} onDownloadClick={onDownloadClick} />,
|
|
31
|
+
});
|
|
32
|
+
}, [imagesRegistry, name, preview, onDownloadClick]);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!preview) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (zoomed) {
|
|
40
|
+
galleryMethods.setActivated(true);
|
|
41
|
+
}
|
|
42
|
+
const imageData = imagesRegistry.get(preview.originalSrc);
|
|
43
|
+
if (imageData) {
|
|
44
|
+
imageData.zoomed = zoomed;
|
|
45
|
+
} else {
|
|
46
|
+
imagesRegistry.set(preview.originalSrc, {
|
|
47
|
+
type: preview.type,
|
|
48
|
+
src: preview.originalSrc,
|
|
49
|
+
label: name,
|
|
50
|
+
zoomed,
|
|
51
|
+
setZoomed,
|
|
52
|
+
actions: <FilePreviewActions url={preview.originalSrc} name={name} onDownloadClick={onDownloadClick} />,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
imagesRegistry.delete(preview.originalSrc);
|
|
58
|
+
};
|
|
59
|
+
}, [galleryMethods, zoomed, preview, imagesRegistry, name, onDownloadClick]);
|
|
60
|
+
|
|
61
|
+
const openGallery = useCallback(() => {
|
|
62
|
+
if (preview) {
|
|
63
|
+
setZoomed(true);
|
|
64
|
+
} else {
|
|
65
|
+
onDownloadClick?.();
|
|
66
|
+
}
|
|
67
|
+
}, [preview, onDownloadClick]);
|
|
68
|
+
|
|
69
|
+
return {openGallery};
|
|
70
|
+
}
|