@fibery/ui-kit 1.17.1 → 1.19.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/index.ts +1 -1
- package/package.json +29 -23
- package/src/antd/styles.ts +1 -1
- package/src/back-button.tsx +3 -0
- package/src/{Button → button}/actions-button.tsx +2 -2
- package/src/{Button → button}/button-base.tsx +2 -2
- package/src/{Button → button}/button-group.tsx +1 -1
- package/src/{Button → button}/button.tsx +3 -3
- package/src/{Button → button}/icon-button.tsx +1 -0
- package/src/button.tsx +3 -0
- package/src/create-inline-theme.ts +2 -0
- package/src/design-system.ts +1009 -0
- package/src/emoji-picker/app-icon-picker.tsx +2 -2
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +7 -7
- package/src/emoji-picker/emoji-picker.tsx +11 -5
- package/src/emoji-picker/icon-emoji-picker.tsx +2 -2
- package/src/emoji-picker/primitives/category.tsx +2 -2
- package/src/emoji-picker/primitives/content.tsx +3 -2
- package/src/emoji-picker/primitives/emoji.tsx +1 -1
- package/src/emoji-picker/primitives/footer.tsx +1 -1
- package/src/emoji-picker/primitives/header.tsx +1 -1
- package/src/emoji-picker/primitives/layout.ts +1 -1
- package/src/emoji-picker/primitives/search.tsx +2 -2
- package/src/emoji-picker/primitives/skin-tone.tsx +2 -2
- package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +3 -3
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +1 -1
- package/src/error-alert.tsx +3 -3
- package/src/form-field-loader.tsx +1 -1
- package/src/icons/Icon.tsx +5 -5
- package/src/icons/ast/Activity.ts +1 -1
- package/src/icons/ast/BellFilled.ts +8 -0
- package/src/icons/ast/BellOff.ts +8 -0
- package/src/icons/ast/BellRinging.ts +8 -0
- package/src/icons/ast/Clock.ts +8 -0
- package/src/icons/ast/ClockAlarm.ts +8 -0
- package/src/icons/ast/Copy.ts +1 -1
- package/src/icons/ast/Export.ts +8 -0
- package/src/icons/ast/ExtensionComments.ts +1 -1
- package/src/icons/ast/Favorites.ts +1 -1
- package/src/icons/ast/FavoritesChecked.ts +1 -1
- package/src/icons/ast/FavoritesOff.ts +8 -0
- package/src/icons/ast/GlobeSimple.ts +8 -0
- package/src/icons/ast/Import.ts +8 -0
- package/src/icons/ast/Lab.ts +8 -0
- package/src/icons/ast/Link.ts +8 -0
- package/src/icons/ast/Monitor.ts +8 -0
- package/src/icons/ast/Network.ts +8 -0
- package/src/icons/ast/Pencil.ts +8 -0
- package/src/icons/ast/People.ts +8 -0
- package/src/icons/ast/RicheditorCommentCreate.ts +1 -1
- package/src/icons/ast/RicheditorLinkCreate.ts +1 -1
- package/src/icons/ast/RicheditorOpenLink.ts +1 -1
- package/src/icons/ast/RicheditorUnlink.ts +1 -1
- package/src/icons/ast/ShieldKeyhole.ts +8 -0
- package/src/icons/ast/Success.ts +8 -0
- package/src/icons/ast/Terminal.ts +8 -0
- package/src/icons/ast/TypeUrl.ts +1 -1
- package/src/icons/ast/WarningTriangle.ts +8 -0
- package/src/icons/ast/index.tsx +19 -4
- package/src/icons/{getIconContainerStyle.tsx → get-icon-container-style.tsx} +1 -1
- package/src/icons/react/BellFilled.tsx +12 -0
- package/src/icons/react/BellOff.tsx +12 -0
- package/src/icons/react/BellRinging.tsx +12 -0
- package/src/icons/react/Clock.tsx +12 -0
- package/src/icons/react/ClockAlarm.tsx +12 -0
- package/src/icons/react/Export.tsx +12 -0
- package/src/icons/react/FavoritesOff.tsx +12 -0
- package/src/icons/react/GlobeSimple.tsx +12 -0
- package/src/icons/react/Import.tsx +12 -0
- package/src/icons/react/Lab.tsx +12 -0
- package/src/icons/react/Link.tsx +12 -0
- package/src/icons/react/Monitor.tsx +12 -0
- package/src/icons/react/Network.tsx +12 -0
- package/src/icons/react/Pencil.tsx +12 -0
- package/src/icons/react/People.tsx +12 -0
- package/src/icons/react/ShieldKeyhole.tsx +12 -0
- package/src/icons/react/Success.tsx +12 -0
- package/src/icons/react/Terminal.tsx +12 -0
- package/src/icons/react/WarningTriangle.tsx +12 -0
- package/src/icons/react/index.tsx +19 -4
- package/src/{Item.tsx → item.tsx} +1 -1
- package/src/loaders.tsx +19 -6
- package/src/loading-sausage.tsx +3 -1
- package/src/select/custom-select-partials/clear-indicator.tsx +22 -0
- package/src/select/custom-select-partials/drop-down-indicator.tsx +26 -0
- package/src/select/custom-select-partials/group-heading.tsx +54 -0
- package/src/select/custom-select-partials/menu.tsx +25 -0
- package/src/select/custom-select-partials/no-option-message.tsx +10 -0
- package/src/select/custom-select-partials/option.tsx +65 -0
- package/src/{Select → select}/index.tsx +54 -48
- package/src/{Select → select}/select-in-popover.tsx +5 -5
- package/src/{Select → select}/styles.ts +9 -53
- package/src/{ThemeProvider.tsx → theme-provider.tsx} +11 -1
- package/src/theme-styles.ts +2 -5
- package/src/toast/primitives.tsx +145 -0
- package/src/toast/toast-action.tsx +20 -0
- package/src/toast/toast-queue.tsx +121 -0
- package/src/toast/toast.tsx +114 -0
- package/src/toast/toaster.tsx +72 -0
- package/src/tooltip.tsx +3 -3
- package/src/BackButton.tsx +0 -3
- package/src/Button.tsx +0 -3
- package/src/Select/components.tsx +0 -90
- package/src/designSystem.ts +0 -951
- package/src/icons/ast/AppTemplatesOneColor.ts +0 -8
- package/src/icons/ast/CopyUrl.ts +0 -8
- package/src/icons/ast/FavoritesMenu.ts +0 -8
- package/src/icons/ast/Markdown.ts +0 -8
- package/src/icons/react/AppTemplatesOneColor.tsx +0 -12
- package/src/icons/react/CopyUrl.tsx +0 -12
- package/src/icons/react/FavoritesMenu.tsx +0 -12
- package/src/icons/react/Markdown.tsx +0 -12
- /package/src/{Button → button}/actions-button-compact.tsx +0 -0
- /package/src/{Button/AddButton.tsx → button/add-button.tsx} +0 -0
- /package/src/{Button/BackButton.tsx → button/back-button.tsx} +0 -0
- /package/src/icons/{generateIconFromAst.ts → generate-icon-from-ast.ts} +0 -0
- /package/src/icons/{IconAsPaths.ts → get-paths.ts} +0 -0
- /package/src/icons/{getShiftStyle.ts → get-shift-style.ts} +0 -0
- /package/src/{Pallete.ts → pallete.ts} +0 -0
- /package/src/{Select → select}/select-control-settings-context.tsx +0 -0
- /package/src/{Select → select}/select-loader.tsx +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {preventDefault} from "@fibery/react/src/prevent-default";
|
|
2
|
+
import {css, cx} from "@linaria/core";
|
|
3
|
+
import * as ToastPrimitives from "@radix-ui/react-toast";
|
|
4
|
+
import {ElementRef, forwardRef} from "react";
|
|
5
|
+
import {IconButton} from "../button/icon-button";
|
|
6
|
+
import {border, space, textStyles, themeVars} from "../design-system";
|
|
7
|
+
import CloseIcon from "../icons/react/Close";
|
|
8
|
+
|
|
9
|
+
export const ToastProvider = ToastPrimitives.Provider;
|
|
10
|
+
|
|
11
|
+
const viewportCss = css`
|
|
12
|
+
position: fixed;
|
|
13
|
+
left: 50%;
|
|
14
|
+
bottom: 0;
|
|
15
|
+
transform: translateX(-50%);
|
|
16
|
+
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column-reverse;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: ${space.s16}px;
|
|
21
|
+
margin: 0;
|
|
22
|
+
z-index: 1010; // inherited from old toast implementation
|
|
23
|
+
padding: 0;
|
|
24
|
+
list-style: none;
|
|
25
|
+
|
|
26
|
+
&:not(:empty) {
|
|
27
|
+
padding: ${space.xl}px; // increased mouse hover area to pause timers of toast
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const ToastViewport = forwardRef<
|
|
32
|
+
ElementRef<typeof ToastPrimitives.Viewport>,
|
|
33
|
+
ToastPrimitives.ToastViewportProps
|
|
34
|
+
>(({className, ...props}, ref) => {
|
|
35
|
+
return <ToastPrimitives.Viewport ref={ref} className={cx(viewportCss, className)} {...props} />;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const rootCss = css`
|
|
39
|
+
user-select: auto !important;
|
|
40
|
+
|
|
41
|
+
background-color: ${themeVars.colorBgToastDefault};
|
|
42
|
+
padding: ${space.m}px ${space.m * 2}px;
|
|
43
|
+
border-radius: ${border.radius6}px;
|
|
44
|
+
box-shadow: ${themeVars.shadowModal};
|
|
45
|
+
|
|
46
|
+
@keyframes hide {
|
|
47
|
+
from {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
}
|
|
50
|
+
to {
|
|
51
|
+
opacity: 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes slideIn {
|
|
56
|
+
from {
|
|
57
|
+
transform: translateY(100%);
|
|
58
|
+
}
|
|
59
|
+
to {
|
|
60
|
+
transform: translateY(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@keyframes swipeOut {
|
|
65
|
+
from {
|
|
66
|
+
transform: translateX(var(--radix-toast-swipe-end-x));
|
|
67
|
+
}
|
|
68
|
+
to {
|
|
69
|
+
transform: translateX(calc(150px + var(--radix-toast-swipe-end-x)));
|
|
70
|
+
opacity: 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&[data-swipe="move"] {
|
|
75
|
+
transform: translateX(var(--radix-toast-swipe-move-x));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&[data-swipe="cancel"] {
|
|
79
|
+
transform: translateX(0);
|
|
80
|
+
transition: transform 200ms ease-out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
84
|
+
will-change: transform, opacity;
|
|
85
|
+
|
|
86
|
+
&[data-state="open"] {
|
|
87
|
+
animation: slideIn 200ms ease-out;
|
|
88
|
+
}
|
|
89
|
+
&[data-state="closed"] {
|
|
90
|
+
animation: hide 200ms ease-out;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&[data-swipe="end"] {
|
|
94
|
+
animation: swipeOut 200ms ease-out;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
export const ToastRoot = forwardRef<ElementRef<typeof ToastPrimitives.Root>, ToastPrimitives.ToastProps>(
|
|
100
|
+
({className, ...props}, ref) => {
|
|
101
|
+
return (
|
|
102
|
+
<ToastPrimitives.Root
|
|
103
|
+
ref={ref}
|
|
104
|
+
className={cx(rootCss, className)}
|
|
105
|
+
onSwipeStart={preventDefault}
|
|
106
|
+
onSwipeMove={preventDefault}
|
|
107
|
+
onSwipeCancel={preventDefault}
|
|
108
|
+
onSwipeEnd={preventDefault}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const titleCss = css`
|
|
116
|
+
${textStyles.heading5};
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
export const ToastTitle = forwardRef<ElementRef<typeof ToastPrimitives.Title>, ToastPrimitives.ToastTitleProps>(
|
|
120
|
+
({className, ...props}, ref) => {
|
|
121
|
+
return <ToastPrimitives.Title ref={ref} className={cx(className, titleCss)} {...props} />;
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const descriptionCss = css`
|
|
126
|
+
${textStyles.small};
|
|
127
|
+
color: ${themeVars.accentTextColor};
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
export const ToastSubtitle = forwardRef<
|
|
131
|
+
ElementRef<typeof ToastPrimitives.Description>,
|
|
132
|
+
ToastPrimitives.ToastDescriptionProps
|
|
133
|
+
>(({className, ...props}, ref) => {
|
|
134
|
+
return <ToastPrimitives.Description ref={ref} className={cx(className, descriptionCss)} {...props} />;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
export const ToastClose = () => {
|
|
138
|
+
return (
|
|
139
|
+
<ToastPrimitives.Close aria-label="Dismiss" asChild>
|
|
140
|
+
<IconButton>
|
|
141
|
+
<CloseIcon iconSize={16} />
|
|
142
|
+
</IconButton>
|
|
143
|
+
</ToastPrimitives.Close>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {Action as RadixToastAction, type ToastActionProps} from "@radix-ui/react-toast";
|
|
2
|
+
import {ElementRef, forwardRef} from "react";
|
|
3
|
+
import {ButtonProps} from "../button/button";
|
|
4
|
+
import {Button} from "../button";
|
|
5
|
+
import {useTheme} from "../theme-provider";
|
|
6
|
+
|
|
7
|
+
export const ToastAction = forwardRef<
|
|
8
|
+
ElementRef<typeof RadixToastAction>,
|
|
9
|
+
ButtonProps & {altText: ToastActionProps["altText"]}
|
|
10
|
+
>(({children, altText, ...props}, ref) => {
|
|
11
|
+
const theme = useTheme();
|
|
12
|
+
return (
|
|
13
|
+
<RadixToastAction ref={ref} altText={altText} asChild>
|
|
14
|
+
<Button color={theme.textColor} {...props}>
|
|
15
|
+
{children}
|
|
16
|
+
</Button>
|
|
17
|
+
</RadixToastAction>
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
export type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {makePubSub} from "@fibery/helpers/utils/pub-sub";
|
|
2
|
+
import type {ToastProps} from "./toast";
|
|
3
|
+
|
|
4
|
+
type AddToastProps = Pick<ToastProps, "type" | "title" | "subTitle" | "icon" | "action" | "autoClose" | "open"> & {
|
|
5
|
+
id?: string;
|
|
6
|
+
};
|
|
7
|
+
type TypedAddProps = Omit<AddToastProps, "type">;
|
|
8
|
+
|
|
9
|
+
type QueuedToast = AddToastProps & {
|
|
10
|
+
id: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ToastQueueOpts = {
|
|
14
|
+
maxActiveToasts?: number;
|
|
15
|
+
};
|
|
16
|
+
export const makeToastQueue = ({maxActiveToasts = 1}: ToastQueueOpts = {}) => {
|
|
17
|
+
const pubSub = makePubSub();
|
|
18
|
+
let queue: QueuedToast[] = [];
|
|
19
|
+
let activeToasts: QueuedToast[] = [];
|
|
20
|
+
|
|
21
|
+
let count = 0;
|
|
22
|
+
|
|
23
|
+
const makeId = () => {
|
|
24
|
+
return `toast-${count++}`;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const updateActiveToasts = () => {
|
|
28
|
+
const freeSlots = maxActiveToasts - activeToasts.length;
|
|
29
|
+
|
|
30
|
+
const newToasts = queue.slice(0, freeSlots);
|
|
31
|
+
queue = queue.slice(freeSlots);
|
|
32
|
+
|
|
33
|
+
activeToasts = activeToasts.concat(newToasts);
|
|
34
|
+
|
|
35
|
+
pubSub.publish();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const closeActive = (id: string) => {
|
|
39
|
+
activeToasts = activeToasts.map((t) => (t.id === id ? {...t, open: false} : t));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const removeFromQueue = (id: string) => {
|
|
43
|
+
queue = queue.filter((queued) => queued.id !== id);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Add toast to queue
|
|
48
|
+
*
|
|
49
|
+
* Pass custom `id` if you don't want toasts to be duplicated.
|
|
50
|
+
* If toast with same id already exists it will be closed to display fresh more relevant one
|
|
51
|
+
*/
|
|
52
|
+
const add = ({id, ...toast}: AddToastProps, {replace = true} = {}) => {
|
|
53
|
+
if (
|
|
54
|
+
id &&
|
|
55
|
+
!replace &&
|
|
56
|
+
(queue.some((queued) => queued.id === id) || activeToasts.some((active) => active.id === id))
|
|
57
|
+
) {
|
|
58
|
+
return id;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (id && replace) {
|
|
62
|
+
closeActive(id);
|
|
63
|
+
removeFromQueue(id);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const t: QueuedToast = {
|
|
67
|
+
id: id || makeId(),
|
|
68
|
+
...toast,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
queue.push(t);
|
|
72
|
+
|
|
73
|
+
updateActiveToasts();
|
|
74
|
+
|
|
75
|
+
return t.id;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
add,
|
|
80
|
+
/** close active toast, play exit animation */
|
|
81
|
+
close(id: string) {
|
|
82
|
+
closeActive(id);
|
|
83
|
+
pubSub.publish();
|
|
84
|
+
},
|
|
85
|
+
/** remove toast from active ones, should be called after exit animation */
|
|
86
|
+
remove(id: string) {
|
|
87
|
+
activeToasts = activeToasts.filter((t) => t.id !== id);
|
|
88
|
+
|
|
89
|
+
updateActiveToasts();
|
|
90
|
+
},
|
|
91
|
+
getActiveToasts() {
|
|
92
|
+
return activeToasts;
|
|
93
|
+
},
|
|
94
|
+
subscribe: pubSub.subscribe,
|
|
95
|
+
unsubscribe: pubSub.unsubscribe,
|
|
96
|
+
|
|
97
|
+
info(t: TypedAddProps) {
|
|
98
|
+
return add(t);
|
|
99
|
+
},
|
|
100
|
+
success(t: TypedAddProps) {
|
|
101
|
+
return add({
|
|
102
|
+
type: "success",
|
|
103
|
+
...t,
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
error(t: TypedAddProps) {
|
|
107
|
+
return add({
|
|
108
|
+
type: "error",
|
|
109
|
+
...t,
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
loading(t: TypedAddProps) {
|
|
113
|
+
return add({
|
|
114
|
+
type: "loading",
|
|
115
|
+
...t,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export type ToastQueue = ReturnType<typeof makeToastQueue>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {useControllableState} from "@fibery/react/src/use-controllable-state";
|
|
2
|
+
import {css} from "@linaria/core";
|
|
3
|
+
import {useState} from "react";
|
|
4
|
+
import {space, themeVars} from "../design-system";
|
|
5
|
+
import Spinner from "../icons/react/Spinner";
|
|
6
|
+
import SuccessIcon from "../icons/react/Success";
|
|
7
|
+
import WarningTriangle from "../icons/react/WarningTriangle";
|
|
8
|
+
import {ToastClose, ToastRoot, ToastSubtitle, ToastTitle} from "./primitives";
|
|
9
|
+
import type {ToastActionElement} from "./toast-action";
|
|
10
|
+
|
|
11
|
+
type ToastType = "info" | "error" | "success" | "loading";
|
|
12
|
+
|
|
13
|
+
export type ToastProps = {
|
|
14
|
+
title: React.ReactNode;
|
|
15
|
+
subTitle?: React.ReactNode;
|
|
16
|
+
icon?: React.ReactNode;
|
|
17
|
+
action?: ToastActionElement;
|
|
18
|
+
autoClose?: boolean;
|
|
19
|
+
open?: boolean;
|
|
20
|
+
onOpenChange?: (open: boolean) => void;
|
|
21
|
+
|
|
22
|
+
type?: ToastType;
|
|
23
|
+
|
|
24
|
+
/** Is called on exit animation end */
|
|
25
|
+
onRemove?: () => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const defaultPropsPerType: Record<ToastType, Partial<ToastProps>> = {
|
|
29
|
+
info: {},
|
|
30
|
+
error: {
|
|
31
|
+
icon: <WarningTriangle color={themeVars.textColor} />,
|
|
32
|
+
autoClose: false,
|
|
33
|
+
},
|
|
34
|
+
loading: {
|
|
35
|
+
icon: <Spinner color={themeVars.textColor} />,
|
|
36
|
+
},
|
|
37
|
+
success: {
|
|
38
|
+
icon: <SuccessIcon color={themeVars.textColor} />,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const rootCss = css`
|
|
43
|
+
min-width: 320px;
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: ${space.l}px;
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
const messageCss = css`
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-grow: 1;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: ${space.xs}px;
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const iconCss = css`
|
|
57
|
+
grid-area: icon;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
export const Toast: React.FC<ToastProps> = (props) => {
|
|
61
|
+
const defaultProps = defaultPropsPerType[props.type || "info"];
|
|
62
|
+
|
|
63
|
+
const {
|
|
64
|
+
title,
|
|
65
|
+
subTitle,
|
|
66
|
+
icon,
|
|
67
|
+
action,
|
|
68
|
+
autoClose = true,
|
|
69
|
+
open,
|
|
70
|
+
onOpenChange,
|
|
71
|
+
onRemove,
|
|
72
|
+
} = {
|
|
73
|
+
...defaultProps,
|
|
74
|
+
...props,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const [isOpen, setOpen] = useControllableState({value: open, defaultValue: true, onChange: onOpenChange});
|
|
78
|
+
|
|
79
|
+
const [noReducedMotion] = useState(() => matchMedia("(prefers-reduced-motion: no-preference)").matches);
|
|
80
|
+
|
|
81
|
+
const close = autoClose ? null : <ToastClose />;
|
|
82
|
+
|
|
83
|
+
const onCloseProps = noReducedMotion
|
|
84
|
+
? {
|
|
85
|
+
onOpenChange: setOpen,
|
|
86
|
+
// https://github.com/radix-ui/primitives/issues/1020
|
|
87
|
+
onAnimationEndCapture() {
|
|
88
|
+
if (!isOpen) {
|
|
89
|
+
onRemove?.();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
: {
|
|
94
|
+
onOpenChange(v: boolean) {
|
|
95
|
+
setOpen(v);
|
|
96
|
+
if (!v) {
|
|
97
|
+
onRemove?.();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<ToastRoot open={open} duration={autoClose ? 5000 : Infinity} className={rootCss} {...onCloseProps}>
|
|
104
|
+
{icon ? <div className={iconCss}>{icon}</div> : null}
|
|
105
|
+
<div className={messageCss}>
|
|
106
|
+
<ToastTitle>{title}</ToastTitle>
|
|
107
|
+
{subTitle ? <ToastSubtitle>{subTitle}</ToastSubtitle> : null}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{action}
|
|
111
|
+
{close}
|
|
112
|
+
</ToastRoot>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {createContext} from "@fibery/react/src/create-context";
|
|
2
|
+
import React, {useEffect, useSyncExternalStore} from "react";
|
|
3
|
+
import {createInlineTheme} from "../create-inline-theme";
|
|
4
|
+
import {colors, getThemeColors} from "../design-system";
|
|
5
|
+
import {ThemeProvider, useThemeMode} from "../theme-provider";
|
|
6
|
+
import {ToastProvider, ToastViewport} from "./primitives";
|
|
7
|
+
import {Toast} from "./toast";
|
|
8
|
+
import type {ToastQueue} from "./toast-queue";
|
|
9
|
+
import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
|
|
10
|
+
import {reactNodeToString} from "@fibery/react/src/react-node-to-string";
|
|
11
|
+
|
|
12
|
+
const ToastThemeProvider: React.FC<React.PropsWithChildren> = ({children}) => {
|
|
13
|
+
const themeMode = useThemeMode();
|
|
14
|
+
const theme = getThemeColors(colors.brandColors.blue, themeMode === "dark" ? "light" : "dark");
|
|
15
|
+
const inlineTheme = createInlineTheme(theme, []);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<ThemeProvider theme={theme}>
|
|
19
|
+
<div style={inlineTheme}>{children}</div>
|
|
20
|
+
</ThemeProvider>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const [Provider, useCtx] = createContext<ToastQueue>("ToastQueue");
|
|
25
|
+
|
|
26
|
+
type OnTrackToast = (args: {title: string; type: string}) => void;
|
|
27
|
+
const TrackToast: React.FC<
|
|
28
|
+
React.PropsWithChildren<{title: React.ReactNode; type: string; onTrackToast: OnTrackToast}>
|
|
29
|
+
> = ({title, type, onTrackToast, children}) => {
|
|
30
|
+
const onTrackCb = useCallbackRef(onTrackToast);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
onTrackCb({title: reactNodeToString(title), type});
|
|
33
|
+
}, [onTrackCb, title, type]);
|
|
34
|
+
|
|
35
|
+
return children as JSX.Element;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Toaster: React.FC<React.PropsWithChildren<{toastQueue: ToastQueue; onTrackToast: OnTrackToast}>> = ({
|
|
39
|
+
toastQueue,
|
|
40
|
+
children,
|
|
41
|
+
onTrackToast,
|
|
42
|
+
}) => {
|
|
43
|
+
const toasts = useSyncExternalStore(toastQueue.subscribe, toastQueue.getActiveToasts);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Provider value={toastQueue}>
|
|
47
|
+
<ToastProvider>
|
|
48
|
+
{children}
|
|
49
|
+
|
|
50
|
+
<ToastThemeProvider>
|
|
51
|
+
{toasts.map(({id, open = true, ...toastProps}) => (
|
|
52
|
+
<TrackToast key={id} title={toastProps.title} type={toastProps.type || "info"} onTrackToast={onTrackToast}>
|
|
53
|
+
<Toast
|
|
54
|
+
{...toastProps}
|
|
55
|
+
open={open}
|
|
56
|
+
onOpenChange={(v) => {
|
|
57
|
+
if (!v) {
|
|
58
|
+
toastQueue.close(id);
|
|
59
|
+
}
|
|
60
|
+
}}
|
|
61
|
+
onRemove={() => toastQueue.remove(id)}
|
|
62
|
+
/>
|
|
63
|
+
</TrackToast>
|
|
64
|
+
))}
|
|
65
|
+
|
|
66
|
+
<ToastViewport />
|
|
67
|
+
</ToastThemeProvider>
|
|
68
|
+
</ToastProvider>
|
|
69
|
+
</Provider>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
export const useToast = useCtx;
|
package/src/tooltip.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {css, cx} from "@linaria/core";
|
|
2
2
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
3
3
|
import {forwardRef, type ReactNode, type SyntheticEvent} from "react";
|
|
4
|
-
import {border, fontWeight, lineHeight, space, themeVars, tooltipDelay} from "./
|
|
4
|
+
import {border, fontWeight, lineHeight, space, themeVars, tooltipDelay} from "./design-system";
|
|
5
5
|
|
|
6
6
|
const preventDefaultAndStopPropagation = (e: SyntheticEvent) => {
|
|
7
7
|
e.preventDefault();
|
|
@@ -93,7 +93,7 @@ export const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps> =
|
|
|
93
93
|
<TooltipPrimitive.Provider disableHoverableContent skipDelayDuration={150} {...props} />
|
|
94
94
|
);
|
|
95
95
|
|
|
96
|
-
export type TooltipProps = Omit<
|
|
96
|
+
export type TooltipProps = Omit<TooltipPrimitive.TooltipTriggerProps, "title"> & {
|
|
97
97
|
title?: ReactNode;
|
|
98
98
|
description?: ReactNode;
|
|
99
99
|
content?: ReactNode;
|
|
@@ -115,7 +115,7 @@ export type TooltipProps = Omit<React.ComponentPropsWithoutRef<"button">, "title
|
|
|
115
115
|
* NOTE:
|
|
116
116
|
* When used together with other triggers (Collapsible, ActionsMenu...) of radix-based component it might
|
|
117
117
|
* overwrite [data-state] attribute of trigger element and make styling a bit harder. As a workaround you might:
|
|
118
|
-
* 1. Make sure that Tooltip is the lowest trigger. Usually we don't care about data-state of tooltip's trigger (e.g. `<CollapsibleTrigger
|
|
118
|
+
* 1. Make sure that Tooltip is the lowest trigger. Usually we don't care about data-state of tooltip's trigger (e.g. `<CollapsibleTrigger asChild><Tooltip><Button/></Tooltip></CollapsibleTrigger>`)
|
|
119
119
|
* 2. Use controlled state of components and add classes for open states
|
|
120
120
|
*
|
|
121
121
|
* Ref: https://github.com/radix-ui/primitives/issues/602
|
package/src/BackButton.tsx
DELETED
package/src/Button.tsx
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import React, {ReactNode} from "react";
|
|
2
|
-
import {css} from "@linaria/core";
|
|
3
|
-
import {components} from "react-windowed-select";
|
|
4
|
-
import RemoveIcon from "../icons/react/Remove";
|
|
5
|
-
import {ClearIndicatorProps, DropdownIndicatorProps, GroupBase, MultiValueRemoveProps, OptionProps} from "react-select";
|
|
6
|
-
import {Button} from "../Button/button";
|
|
7
|
-
import {space, themeVars} from "../designSystem";
|
|
8
|
-
import ArrowCollapseVertical from "../icons/react/ArrowCollapseVertical";
|
|
9
|
-
import {expanderExpandedStyle, expanderStyle} from "./styles";
|
|
10
|
-
import cn from "classnames";
|
|
11
|
-
|
|
12
|
-
export const Option = <
|
|
13
|
-
TOption,
|
|
14
|
-
IsMulti extends boolean = boolean,
|
|
15
|
-
Group extends GroupBase<TOption> = GroupBase<TOption>
|
|
16
|
-
>({
|
|
17
|
-
children,
|
|
18
|
-
...props
|
|
19
|
-
}: OptionProps<TOption, IsMulti, Group>) => {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
-
const {onMouseMove, onMouseOver, ...rest} = props.innerProps;
|
|
22
|
-
const newProps = Object.assign(props, {innerProps: rest});
|
|
23
|
-
return <components.Option {...newProps}>{children}</components.Option>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export function DropdownIndicator<
|
|
27
|
-
TOption,
|
|
28
|
-
IsMulti extends boolean = boolean,
|
|
29
|
-
Group extends GroupBase<TOption> = GroupBase<TOption>
|
|
30
|
-
>(props: DropdownIndicatorProps<TOption, IsMulti, Group>) {
|
|
31
|
-
if (props.selectProps.isDisabled) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
return (
|
|
35
|
-
<div className={cn(expanderStyle, props.selectProps.menuIsOpen && expanderExpandedStyle)}>
|
|
36
|
-
<ArrowCollapseVertical color={themeVars.disabledTextColor} />
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function ClearIndicator<
|
|
42
|
-
TOption,
|
|
43
|
-
IsMulti extends boolean = boolean,
|
|
44
|
-
Group extends GroupBase<TOption> = GroupBase<TOption>
|
|
45
|
-
>({
|
|
46
|
-
innerProps,
|
|
47
|
-
selectProps,
|
|
48
|
-
}: ClearIndicatorProps<TOption, IsMulti, Group> | MultiValueRemoveProps<TOption, IsMulti, Group>) {
|
|
49
|
-
if (selectProps.isDisabled) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
return (
|
|
53
|
-
<div {...innerProps}>
|
|
54
|
-
<Button borderless Icon={RemoveIcon} disabled={selectProps.isDisabled} size={":button-size/super-small"} />
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const NoOptionsMessage = ({children}: {children: ReactNode}) => {
|
|
60
|
-
return (
|
|
61
|
-
<div
|
|
62
|
-
className={css`
|
|
63
|
-
${{
|
|
64
|
-
paddingLeft: space.l + 2,
|
|
65
|
-
paddingRight: space.l + 2,
|
|
66
|
-
paddingTop: space.m,
|
|
67
|
-
paddingBottom: space.m,
|
|
68
|
-
}}
|
|
69
|
-
`}
|
|
70
|
-
>
|
|
71
|
-
{children}
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const groupDividerContainerStyle = css`
|
|
77
|
-
padding: ${space.l}px 0;
|
|
78
|
-
box-sizing: content-box;
|
|
79
|
-
`;
|
|
80
|
-
|
|
81
|
-
const groupDividerStyle = css`
|
|
82
|
-
width: 100%;
|
|
83
|
-
border-top: 1px solid #eeeff1;
|
|
84
|
-
`;
|
|
85
|
-
|
|
86
|
-
export const GroupDivider = () => (
|
|
87
|
-
<div className={groupDividerContainerStyle}>
|
|
88
|
-
<div className={groupDividerStyle}></div>
|
|
89
|
-
</div>
|
|
90
|
-
);
|