@fibery/ui-kit 1.40.3 → 1.41.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/CHANGELOG.md +14 -0
- package/eslint.config.mjs +16 -0
- package/package.json +11 -13
- package/src/a11y-color.test.ts +162 -0
- package/src/a11y-color.ts +13 -20
- package/src/actions-menu/actions-menu-item.tsx +9 -12
- package/src/actions-menu/context-actions-menu.tsx +8 -3
- package/src/ai/model.tsx +0 -1
- package/src/ai/temperature.tsx +0 -1
- package/src/animated-height-container.tsx +3 -3
- package/src/antd/ant-modal.tsx +10 -5
- package/src/antd/index.tsx +3 -0
- package/src/antd/input.tsx +0 -1
- package/src/antd/styles.ts +15 -15
- package/src/app-icon-with-fallback.tsx +6 -6
- package/src/app-icon-wrapper.tsx +2 -3
- package/src/app-icon.tsx +4 -4
- package/src/avatar.tsx +3 -3
- package/src/button/base-button.tsx +0 -1
- package/src/button/button.tsx +1 -0
- package/src/button/make-button-colors.ts +5 -13
- package/src/checkbox.tsx +2 -2
- package/src/collapsible-section.tsx +11 -1
- package/src/color-picker/ColorPickerOrLoader.js +2 -2
- package/src/color-utils.test.ts +307 -0
- package/src/color-utils.ts +215 -0
- package/src/command-menu/index.tsx +1 -0
- package/src/comment.tsx +3 -2
- package/src/context-menu/index.tsx +12 -7
- package/src/date-picker/contexts.ts +2 -2
- package/src/date-picker/date-range-picker.tsx +3 -4
- package/src/date-picker/single-date-picker.tsx +147 -119
- package/src/date-picker/types.ts +4 -3
- package/src/day-select/iso-week-day-select.tsx +2 -2
- package/src/day-select/week-day-select.tsx +2 -2
- package/src/delayed.tsx +0 -1
- package/src/design-system/alpha.test.ts +59 -0
- package/src/design-system/alpha.ts +41 -0
- package/src/design-system/animation.ts +10 -0
- package/src/design-system/colors-css.test.ts +39 -0
- package/src/design-system/colors-css.ts +25 -0
- package/src/design-system/colors-js.test.ts +232 -0
- package/src/design-system/colors-js.ts +107 -0
- package/src/design-system/colors.test.ts +74 -0
- package/src/design-system/colors.ts +759 -0
- package/src/design-system/date.ts +3 -0
- package/src/design-system/layout.ts +106 -0
- package/src/design-system/theme.test.ts +94 -0
- package/src/design-system/theme.ts +93 -0
- package/src/design-system/typography.ts +179 -0
- package/src/design-system/vars.test.ts +1679 -0
- package/src/design-system/vars.ts +52 -0
- package/src/design-system.test.ts +45 -22
- package/src/design-system.ts +25 -1339
- 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 +3 -3
- package/src/favorites-icon.tsx +1 -1
- package/src/fibermoji-placeholder.tsx +3 -3
- package/src/field-container.tsx +11 -2
- 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 +32 -348
- package/src/file-item.tsx +6 -3
- package/src/hue-shift.test.ts +91 -0
- package/src/icons/ast/ChatBubble.ts +8 -0
- package/src/icons/ast/ChatFloat.ts +8 -0
- package/src/icons/ast/ChatSidebar.ts +8 -0
- package/src/icons/ast/FileCounter.ts +8 -0
- package/src/icons/ast/FileMultiple.ts +8 -0
- package/src/icons/ast/FileOther.ts +8 -0
- package/src/icons/ast/NoBorder.ts +8 -0
- package/src/icons/ast/NoFill.ts +8 -0
- package/src/icons/ast/ValueEdit.ts +8 -0
- package/src/icons/ast/index.tsx +9 -0
- package/src/icons/react/ChatBubble.tsx +13 -0
- package/src/icons/react/ChatFloat.tsx +13 -0
- package/src/icons/react/ChatSidebar.tsx +13 -0
- package/src/icons/react/FileCounter.tsx +13 -0
- package/src/icons/react/FileMultiple.tsx +13 -0
- package/src/icons/react/FileOther.tsx +13 -0
- package/src/icons/react/NoBorder.tsx +13 -0
- package/src/icons/react/NoFill.tsx +13 -0
- package/src/icons/react/ValueEdit.tsx +13 -0
- package/src/icons/react/index.tsx +9 -0
- package/src/icons/svg/chat-bubble.svg +4 -0
- package/src/icons/svg/chat-float.svg +4 -0
- package/src/icons/svg/chat-sidebar.svg +4 -0
- package/src/icons/svg/file-counter.svg +3 -0
- package/src/icons/svg/file-multiple.svg +3 -0
- package/src/icons/svg/file-other.svg +3 -0
- package/src/icons/svg/no-border.svg +17 -0
- package/src/icons/svg/no-fill.svg +4 -0
- package/src/icons/svg/value-edit.svg +3 -0
- package/src/images-gallery/images-gallery.tsx +8 -6
- package/src/images-gallery/slide-buttons.tsx +4 -11
- package/src/is-iOS.ts +0 -1
- package/src/is-in-popup.ts +2 -1
- package/src/lists/actions-menu-row-surface.tsx +7 -7
- package/src/loading-sausage.tsx +2 -2
- package/src/media-query-utils.ts +1 -2
- package/src/mobile-keyboard-aware-popup.tsx +6 -5
- package/src/modal-menu/modal-menu-content.tsx +2 -2
- package/src/number-input/decimal.js +9 -7
- package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
- package/src/number-input/number-input-inline.tsx +118 -0
- package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
- package/src/number-input/number-input.tsx +63 -121
- package/src/number-input/types.ts +19 -0
- package/src/number-input/utils.ts +61 -0
- package/src/online-users.tsx +2 -2
- package/src/palette-generator.test.ts +309 -0
- package/src/palette-generator.ts +160 -0
- package/src/palettes/_.ts +72 -0
- package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-arch.ts +188 -0
- package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-user.ts +187 -0
- package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-arch.ts +222 -0
- package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-user.ts +222 -0
- package/src/platform.ts +0 -3
- package/src/popover/get-element-ref.ts +28 -0
- package/src/popover/index.tsx +236 -339
- package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
- package/src/popover/mobile-popover.tsx +169 -0
- package/src/popover/modifiers.tsx +2 -2
- package/src/popover/popup-stack-context.tsx +8 -9
- package/src/progress.tsx +2 -2
- package/src/reactions/reaction-button.tsx +12 -6
- package/src/root-theme-provider.test.tsx +411 -0
- package/src/scale-generator.ts +356 -0
- package/src/select/components/menu-list-virtualized.tsx +12 -25
- package/src/select/components/menu.tsx +12 -2
- package/src/select/index.tsx +6 -5
- package/src/select/select.tsx +38 -39
- package/src/select/styles.ts +0 -1
- package/src/select/util.ts +1 -1
- package/src/static-palettes.ts +356 -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 +370 -0
- package/src/thematic.tsx +386 -0
- package/src/theme-provider.test.tsx +820 -0
- package/src/theme-provider.tsx +158 -92
- package/src/theme-settings.ts +67 -12
- package/src/theme-styles.ts +58 -6
- package/src/toast/toast-action.tsx +1 -1
- package/src/toast/toast.tsx +1 -2
- package/src/toggle-on-off.tsx +2 -2
- package/src/toggle.tsx +7 -8
- package/src/tooltip.tsx +14 -10
- package/src/type-badge.tsx +7 -14
- package/src/unit/styles.ts +2 -25
- package/src/unit/unit-with-tooltip.tsx +3 -2
- package/src/use-is-phone.tsx +7 -2
- package/src/use-long-press.tsx +2 -2
- package/src/use-on-screen-keyboard-data.tsx +2 -2
- package/src/with-data.tsx +4 -3
- package/src/workflow-progress-icon.tsx +2 -2
- package/.eslintignore +0 -3
- package/.eslintrc +0 -14
- package/src/__mocks__/createInlineTheme.js +0 -3
- package/src/create-inline-theme.ts +0 -66
- package/src/number-input/index.js +0 -191
- package/src/palette.ts +0 -237
|
@@ -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 {RadixPortalThemeProvider} 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
|
+
<RadixPortalThemeProvider>
|
|
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
|
+
</RadixPortalThemeProvider>
|
|
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
|
+
<RadixPortalThemeProvider>
|
|
162
|
+
<DropdownMenuPrimitive.SubContent
|
|
163
|
+
ref={ref}
|
|
164
|
+
className={cx(dropdownMenuContentStyles, className)}
|
|
165
|
+
collisionPadding={collisionPadding}
|
|
166
|
+
{...rest}
|
|
167
|
+
/>
|
|
168
|
+
</RadixPortalThemeProvider>
|
|
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
|
-
import
|
|
2
|
+
import compact from "lodash/compact";
|
|
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"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import memoize from "lodash/memoize";
|
|
2
2
|
import {css} from "@linaria/core";
|
|
3
3
|
import {FC, useEffect, useRef} from "react";
|
|
4
4
|
import {textStyles} from "./design-system";
|
|
@@ -38,12 +38,12 @@ const mouths = [
|
|
|
38
38
|
`<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16" viewBox="0 0 32 16" fill="none"><g clip-path="url(#clip0_31_1134)"><path d="M4.23177 12.4853C2.41601 11.1761 1.06315 9.59547 0.249133 7.87572C-0.702621 5.86498 1.22002 4 3.51791 4L7 4C7.55229 4 8 4.44772 8 5V13.0522C8 13.7579 7.28869 14.2398 6.6548 13.9296C5.79179 13.5074 4.97984 13.0247 4.23177 12.4853Z" fill="currentColor"/><path d="M31.7509 7.87572C30.9369 9.59547 29.584 11.1761 27.7682 12.4853C27.0202 13.0247 26.2082 13.5074 25.3452 13.9296C24.7113 14.2398 24 13.7579 24 13.0522L24 5C24 4.44772 24.4477 4 25 4L28.4821 4C30.78 4 32.7026 5.86498 31.7509 7.87572Z" fill="currentColor"/><path d="M16 16C14.564 16 13.1472 15.8662 11.7816 15.6082C11.3227 15.5215 11 15.1143 11 14.6473V5C11 4.44772 11.4477 4 12 4L20 4C20.5523 4 21 4.44772 21 5V14.6473C21 15.1143 20.6773 15.5215 20.2184 15.6082C18.8528 15.8662 17.436 16 16 16Z" fill="currentColor"/></g><defs><clipPath id="clip0_31_1134"><rect width="32" height="16" fill="white"/></clipPath></defs></svg>`,
|
|
39
39
|
];
|
|
40
40
|
|
|
41
|
-
export const getColors =
|
|
41
|
+
export const getColors = memoize((v: string) => {
|
|
42
42
|
const idx = Math.floor((cyrb53(v) / Math.pow(2, 53)) * colors.length);
|
|
43
43
|
return colors[idx];
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
const getMouth =
|
|
46
|
+
const getMouth = memoize((v: string) => {
|
|
47
47
|
const salted = v + "::mouth"; // made mouths independent of colors
|
|
48
48
|
const idx = Math.floor((cyrb53(salted) / Math.pow(2, 53)) * mouths.length);
|
|
49
49
|
return mouths[idx];
|
package/src/field-container.tsx
CHANGED
|
@@ -20,18 +20,27 @@ type Props = {
|
|
|
20
20
|
label?: string;
|
|
21
21
|
collapsible?: boolean;
|
|
22
22
|
collapsed?: boolean;
|
|
23
|
+
collapsedDefault?: boolean;
|
|
23
24
|
onCollapseChange?: (collapsed: boolean) => void;
|
|
24
25
|
badge?: ReactNode;
|
|
25
26
|
children: ReactNode;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
export const FieldContainer = ({
|
|
29
|
+
export const FieldContainer = ({
|
|
30
|
+
label,
|
|
31
|
+
collapsible = false,
|
|
32
|
+
collapsed,
|
|
33
|
+
collapsedDefault = true,
|
|
34
|
+
onCollapseChange,
|
|
35
|
+
badge,
|
|
36
|
+
children,
|
|
37
|
+
}: Props) => {
|
|
29
38
|
return (
|
|
30
39
|
<CollapsibleSection
|
|
31
40
|
label={label ? <div className={labelStyle}>{label}</div> : undefined}
|
|
32
41
|
collapsible={collapsible}
|
|
33
42
|
collapsed={collapsed}
|
|
34
|
-
collapsedDefault={
|
|
43
|
+
collapsedDefault={collapsedDefault}
|
|
35
44
|
onCollapsedChange={onCollapseChange}
|
|
36
45
|
badge={badge}
|
|
37
46
|
>
|
|
@@ -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 FileOther from "../icons/react/FileOther";
|
|
8
|
+
|
|
9
|
+
export function getFileIconComponent(contentType?: string) {
|
|
10
|
+
if (!contentType) {
|
|
11
|
+
return FileOther;
|
|
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 FileOther;
|
|
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
|
+
}
|