@redsift/popovers 9.2.3-patch → 9.2.3
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/coverage/clover.xml +763 -0
- package/coverage/coverage-final.json +53 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/dialog/Dialog.tsx.html +271 -0
- package/coverage/lcov-report/dialog/context.ts.html +97 -0
- package/coverage/lcov-report/dialog/index.html +191 -0
- package/coverage/lcov-report/dialog/index.ts.html +100 -0
- package/coverage/lcov-report/dialog/types.ts.html +241 -0
- package/coverage/lcov-report/dialog/useDialog.tsx.html +346 -0
- package/coverage/lcov-report/dialog/useDialogContext.tsx.html +121 -0
- package/coverage/lcov-report/dialog-content/DialogContent.tsx.html +484 -0
- package/coverage/lcov-report/dialog-content/index.html +146 -0
- package/coverage/lcov-report/dialog-content/index.ts.html +91 -0
- package/coverage/lcov-report/dialog-content/intl/index.html +116 -0
- package/coverage/lcov-report/dialog-content/intl/index.ts.html +106 -0
- package/coverage/lcov-report/dialog-content/styles.ts.html +256 -0
- package/coverage/lcov-report/dialog-content-actions/DialogContentActions.tsx.html +205 -0
- package/coverage/lcov-report/dialog-content-actions/index.html +146 -0
- package/coverage/lcov-report/dialog-content-actions/index.ts.html +91 -0
- package/coverage/lcov-report/dialog-content-actions/styles.ts.html +139 -0
- package/coverage/lcov-report/dialog-content-body/DialogContentBody.tsx.html +232 -0
- package/coverage/lcov-report/dialog-content-body/index.html +146 -0
- package/coverage/lcov-report/dialog-content-body/index.ts.html +91 -0
- package/coverage/lcov-report/dialog-content-body/styles.ts.html +259 -0
- package/coverage/lcov-report/dialog-content-header/DialogContentHeader.tsx.html +280 -0
- package/coverage/lcov-report/dialog-content-header/index.html +146 -0
- package/coverage/lcov-report/dialog-content-header/index.ts.html +91 -0
- package/coverage/lcov-report/dialog-content-header/styles.ts.html +193 -0
- package/coverage/lcov-report/dialog-trigger/DialogTrigger.tsx.html +217 -0
- package/coverage/lcov-report/dialog-trigger/index.html +131 -0
- package/coverage/lcov-report/dialog-trigger/index.ts.html +91 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +341 -0
- package/coverage/lcov-report/popover/Popover.tsx.html +295 -0
- package/coverage/lcov-report/popover/context.ts.html +97 -0
- package/coverage/lcov-report/popover/index.html +191 -0
- package/coverage/lcov-report/popover/index.ts.html +100 -0
- package/coverage/lcov-report/popover/types.ts.html +283 -0
- package/coverage/lcov-report/popover/usePopover.tsx.html +415 -0
- package/coverage/lcov-report/popover/usePopoverContext.tsx.html +121 -0
- package/coverage/lcov-report/popover-content/PopoverContent.tsx.html +229 -0
- package/coverage/lcov-report/popover-content/index.html +146 -0
- package/coverage/lcov-report/popover-content/index.ts.html +94 -0
- package/coverage/lcov-report/popover-content/styles.ts.html +370 -0
- package/coverage/lcov-report/popover-trigger/PopoverTrigger.tsx.html +202 -0
- package/coverage/lcov-report/popover-trigger/index.html +131 -0
- package/coverage/lcov-report/popover-trigger/index.ts.html +91 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/toast/Toast.tsx.html +373 -0
- package/coverage/lcov-report/toast/index.html +161 -0
- package/coverage/lcov-report/toast/index.ts.html +91 -0
- package/coverage/lcov-report/toast/intl/index.html +116 -0
- package/coverage/lcov-report/toast/intl/index.ts.html +106 -0
- package/coverage/lcov-report/toast/styles.ts.html +193 -0
- package/coverage/lcov-report/toast/types.ts.html +217 -0
- package/coverage/lcov-report/toast-container/ToastContainer.tsx.html +217 -0
- package/coverage/lcov-report/toast-container/index.html +161 -0
- package/coverage/lcov-report/toast-container/index.ts.html +94 -0
- package/coverage/lcov-report/toast-container/styles.ts.html +2284 -0
- package/coverage/lcov-report/toast-container/useToast.tsx.html +469 -0
- package/coverage/lcov-report/tooltip/Tooltip.tsx.html +250 -0
- package/coverage/lcov-report/tooltip/context.ts.html +97 -0
- package/coverage/lcov-report/tooltip/index.html +191 -0
- package/coverage/lcov-report/tooltip/index.ts.html +100 -0
- package/coverage/lcov-report/tooltip/types.ts.html +250 -0
- package/coverage/lcov-report/tooltip/useTooltip.tsx.html +358 -0
- package/coverage/lcov-report/tooltip/useTooltipContext.tsx.html +121 -0
- package/coverage/lcov-report/tooltip-content/TooltipContent.tsx.html +313 -0
- package/coverage/lcov-report/tooltip-content/index.html +146 -0
- package/coverage/lcov-report/tooltip-content/index.ts.html +91 -0
- package/coverage/lcov-report/tooltip-content/styles.ts.html +337 -0
- package/coverage/lcov-report/tooltip-trigger/TooltipTrigger.tsx.html +211 -0
- package/coverage/lcov-report/tooltip-trigger/index.html +131 -0
- package/coverage/lcov-report/tooltip-trigger/index.ts.html +91 -0
- package/coverage/lcov.info +1510 -0
- package/coverage/storybook/coverage-storybook.json +58724 -0
- package/dist/package.json +96 -0
- package/index.ts +1 -0
- package/jest.config.js +3 -0
- package/package.json +2 -3
- package/rollup.config.js +13 -0
- package/src/components/dialog/Dialog.stories.tsx +264 -0
- package/src/components/dialog/Dialog.test.tsx +116 -0
- package/src/components/dialog/Dialog.tsx +62 -0
- package/src/components/dialog/context.ts +4 -0
- package/src/components/dialog/index.ts +5 -0
- package/src/components/dialog/types.ts +52 -0
- package/src/components/dialog/useDialog.tsx +87 -0
- package/src/components/dialog/useDialogContext.tsx +12 -0
- package/src/components/dialog-content/DialogContent.stories.tsx +348 -0
- package/src/components/dialog-content/DialogContent.tsx +133 -0
- package/src/components/dialog-content/index.ts +2 -0
- package/src/components/dialog-content/intl/en-US.json +3 -0
- package/src/components/dialog-content/intl/fr-FR.json +3 -0
- package/src/components/dialog-content/intl/index.ts +7 -0
- package/src/components/dialog-content/styles.ts +57 -0
- package/src/components/dialog-content/types.ts +10 -0
- package/src/components/dialog-content-actions/DialogContentActions.test.tsx +68 -0
- package/src/components/dialog-content-actions/DialogContentActions.tsx +40 -0
- package/src/components/dialog-content-actions/index.ts +2 -0
- package/src/components/dialog-content-actions/styles.ts +18 -0
- package/src/components/dialog-content-actions/types.ts +11 -0
- package/src/components/dialog-content-body/DialogContentBody.test.tsx +63 -0
- package/src/components/dialog-content-body/DialogContentBody.tsx +49 -0
- package/src/components/dialog-content-body/index.ts +2 -0
- package/src/components/dialog-content-body/styles.ts +58 -0
- package/src/components/dialog-content-body/types.ts +14 -0
- package/src/components/dialog-content-header/DialogContentHeader.test.tsx +63 -0
- package/src/components/dialog-content-header/DialogContentHeader.tsx +65 -0
- package/src/components/dialog-content-header/index.ts +2 -0
- package/src/components/dialog-content-header/styles.ts +36 -0
- package/src/components/dialog-content-header/types.ts +21 -0
- package/src/components/dialog-trigger/DialogTrigger.tsx +44 -0
- package/src/components/dialog-trigger/index.ts +2 -0
- package/src/components/dialog-trigger/types.ts +9 -0
- package/src/components/popover/Popover.stories.tsx +129 -0
- package/src/components/popover/Popover.test.tsx +102 -0
- package/src/components/popover/Popover.tsx +70 -0
- package/src/components/popover/context.ts +4 -0
- package/src/components/popover/index.ts +5 -0
- package/src/components/popover/types.ts +66 -0
- package/src/components/popover/usePopover.tsx +110 -0
- package/src/components/popover/usePopoverContext.tsx +12 -0
- package/src/components/popover-content/PopoverContent.tsx +48 -0
- package/src/components/popover-content/index.ts +3 -0
- package/src/components/popover-content/styles.ts +95 -0
- package/src/components/popover-content/types.ts +11 -0
- package/src/components/popover-trigger/PopoverTrigger.tsx +39 -0
- package/src/components/popover-trigger/index.ts +2 -0
- package/src/components/popover-trigger/types.ts +9 -0
- package/src/components/toast/Toast.stories.tsx +68 -0
- package/src/components/toast/Toast.test.tsx +63 -0
- package/src/components/toast/Toast.tsx +96 -0
- package/src/components/toast/index.ts +2 -0
- package/src/components/toast/intl/en-US.json +3 -0
- package/src/components/toast/intl/fr-FR.json +3 -0
- package/src/components/toast/intl/index.ts +7 -0
- package/src/components/toast/styles.ts +36 -0
- package/src/components/toast/types.ts +44 -0
- package/src/components/toast-container/ToastContainer.stories.tsx +349 -0
- package/src/components/toast-container/ToastContainer.tsx +44 -0
- package/src/components/toast-container/index.ts +3 -0
- package/src/components/toast-container/styles.ts +733 -0
- package/src/components/toast-container/types.ts +110 -0
- package/src/components/toast-container/useToast.test.tsx +111 -0
- package/src/components/toast-container/useToast.tsx +128 -0
- package/src/components/tooltip/Tooltip.stories.tsx +196 -0
- package/src/components/tooltip/Tooltip.test.tsx +119 -0
- package/src/components/tooltip/Tooltip.tsx +55 -0
- package/src/components/tooltip/context.ts +4 -0
- package/src/components/tooltip/index.ts +5 -0
- package/src/components/tooltip/types.ts +55 -0
- package/src/components/tooltip/useTooltip.tsx +93 -0
- package/src/components/tooltip/useTooltipContext.tsx +12 -0
- package/src/components/tooltip-content/TooltipContent.tsx +76 -0
- package/src/components/tooltip-content/index.ts +2 -0
- package/src/components/tooltip-content/styles.ts +84 -0
- package/src/components/tooltip-content/types.ts +14 -0
- package/src/components/tooltip-trigger/TooltipTrigger.tsx +42 -0
- package/src/components/tooltip-trigger/index.ts +2 -0
- package/src/components/tooltip-trigger/types.ts +9 -0
- package/src/index.ts +16 -0
- package/tsconfig.json +3 -0
- /package/{CONTRIBUTING.md → dist/CONTRIBUTING.md} +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{index.js.map → dist/index.js.map} +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ClearWaitingQueueParams } from 'react-toastify';
|
|
3
|
+
import { ToastPlacement, ToastVariant, ToastProps } from '../toast';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Component props.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToastContainerProps {
|
|
9
|
+
/** Delay in ms to close the toast. If set to false, the notification needs to be closed manually. */
|
|
10
|
+
autoClose?: number | false;
|
|
11
|
+
/** Dismiss toast on click. */
|
|
12
|
+
closeOnClick?: boolean;
|
|
13
|
+
/** Allow Toasts to be draggable. */
|
|
14
|
+
draggable?: boolean;
|
|
15
|
+
/** Whether the progress bar is displayed or not on all Toasts. */
|
|
16
|
+
hideProgressBar?: boolean;
|
|
17
|
+
/** Used to limit the number of toast displayed on screen at the same time. */
|
|
18
|
+
limit?: number;
|
|
19
|
+
/** Pause the timer when the window loses focus. */
|
|
20
|
+
pauseOnFocusLoss?: boolean;
|
|
21
|
+
/** Keep the timer running or not on hover. */
|
|
22
|
+
pauseOnHover?: boolean;
|
|
23
|
+
/** Default placement for all Toasts. */
|
|
24
|
+
placement?: ToastPlacement;
|
|
25
|
+
/** Supports right to left content. */
|
|
26
|
+
rtl?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type StyledToastContainerProps = ToastContainerProps & {};
|
|
30
|
+
|
|
31
|
+
export interface ToastOptions {
|
|
32
|
+
/** Delay in ms to close the toast. If set to false, the notification needs to be closed manually. */
|
|
33
|
+
autoClose?: number | false;
|
|
34
|
+
/** Dismiss toast on click. */
|
|
35
|
+
closeOnClick?: boolean;
|
|
36
|
+
/** Content. */
|
|
37
|
+
content?: ReactNode;
|
|
38
|
+
/** Let you delay the toast appearance. Pass a value in ms. */
|
|
39
|
+
delay?: number;
|
|
40
|
+
/** Allow toast to be draggable. */
|
|
41
|
+
draggable?: boolean;
|
|
42
|
+
/** Whether the component has a close button or not. */
|
|
43
|
+
closeButton?: boolean | ReactNode;
|
|
44
|
+
/** Whether or not the progress bar is displayed. */
|
|
45
|
+
hideProgressBar?: boolean;
|
|
46
|
+
/** Pause the timer when the window loses focus. */
|
|
47
|
+
pauseOnFocusLoss?: boolean;
|
|
48
|
+
/** Keep the timer running or not on hover. */
|
|
49
|
+
pauseOnHover?: boolean;
|
|
50
|
+
/** Placement of the Toast. */
|
|
51
|
+
placement?: ToastPlacement;
|
|
52
|
+
/** Title. */
|
|
53
|
+
title?: string;
|
|
54
|
+
/** Variant */
|
|
55
|
+
variant?: ToastVariant;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type Id = number | string;
|
|
59
|
+
|
|
60
|
+
export type useToastReturnType = {
|
|
61
|
+
notify: (
|
|
62
|
+
options: ToastOptions,
|
|
63
|
+
props?: Omit<ToastProps, 'ref' | 'closeButton'>
|
|
64
|
+
) => Id;
|
|
65
|
+
clearWaitingQueue: (params?: ClearWaitingQueueParams | undefined) => void;
|
|
66
|
+
dismiss: (id?: Id | undefined) => void;
|
|
67
|
+
done: (id: Id) => void;
|
|
68
|
+
error: (
|
|
69
|
+
options: Omit<ToastOptions, 'variant'>,
|
|
70
|
+
props?: Omit<ToastProps, 'ref'>
|
|
71
|
+
) => Id;
|
|
72
|
+
isActive: (id: Id) => boolean;
|
|
73
|
+
info: (
|
|
74
|
+
options: Omit<ToastOptions, 'variant'>,
|
|
75
|
+
props?: Omit<ToastProps, 'ref'>
|
|
76
|
+
) => Id;
|
|
77
|
+
loading: (
|
|
78
|
+
options: Omit<ToastOptions, 'variant'>,
|
|
79
|
+
props?: Omit<ToastProps, 'ref'>
|
|
80
|
+
) => Id;
|
|
81
|
+
promise: (
|
|
82
|
+
promise: Promise<unknown> | (() => Promise<unknown>),
|
|
83
|
+
{
|
|
84
|
+
pending,
|
|
85
|
+
success,
|
|
86
|
+
error,
|
|
87
|
+
}: {
|
|
88
|
+
pending: Pick<ToastOptions, 'content' | 'title' | 'variant'>;
|
|
89
|
+
success: Pick<ToastOptions, 'content' | 'title' | 'variant'>;
|
|
90
|
+
error: Pick<ToastOptions, 'content' | 'title' | 'variant'>;
|
|
91
|
+
},
|
|
92
|
+
options?: Omit<ToastOptions, 'content' | 'title' | 'variant'>,
|
|
93
|
+
props?: Omit<ToastProps, 'ref'>
|
|
94
|
+
) => void;
|
|
95
|
+
success: (
|
|
96
|
+
options: Omit<ToastOptions, 'variant'>,
|
|
97
|
+
props?: Omit<ToastProps, 'ref'>
|
|
98
|
+
) => Id;
|
|
99
|
+
update: (
|
|
100
|
+
id: number | string,
|
|
101
|
+
{ content, placement, title, variant, ...options }: ToastOptions,
|
|
102
|
+
props?: Omit<ToastProps, 'ref'>
|
|
103
|
+
) => void;
|
|
104
|
+
warning: (
|
|
105
|
+
options: Omit<ToastOptions, 'variant'>,
|
|
106
|
+
props?: Omit<ToastProps, 'ref'>
|
|
107
|
+
) => Id;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export type useToastProps = () => useToastReturnType;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { screen, render, act, waitFor } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
import { ToastContainer, useToast } from '.';
|
|
5
|
+
|
|
6
|
+
const InstantToast: React.FC<unknown> = () => {
|
|
7
|
+
const toastId = React.useRef<number | string | null>(null);
|
|
8
|
+
const toast2Id = React.useRef<number | string | null>(null);
|
|
9
|
+
const { promise, notify, update, success, warning, error, info, loading } =
|
|
10
|
+
useToast();
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
toastId.current = notify({
|
|
14
|
+
title: 'Saving...',
|
|
15
|
+
variant: 'loading',
|
|
16
|
+
autoClose: false,
|
|
17
|
+
closeButton: false,
|
|
18
|
+
});
|
|
19
|
+
update(toastId.current, {
|
|
20
|
+
title: 'Saved!',
|
|
21
|
+
autoClose: 5000,
|
|
22
|
+
variant: 'loading',
|
|
23
|
+
placement: 'bottom-center',
|
|
24
|
+
});
|
|
25
|
+
toast2Id.current = notify({
|
|
26
|
+
title: 'Saving again...',
|
|
27
|
+
autoClose: false,
|
|
28
|
+
closeButton: false,
|
|
29
|
+
});
|
|
30
|
+
update(toast2Id.current, {
|
|
31
|
+
title: 'Saved again!',
|
|
32
|
+
autoClose: 5000,
|
|
33
|
+
});
|
|
34
|
+
promise(
|
|
35
|
+
Promise.resolve(),
|
|
36
|
+
{
|
|
37
|
+
pending: { title: 'Promise is pending' },
|
|
38
|
+
success: { title: 'Promise resolved!' },
|
|
39
|
+
error: { title: 'Promise rejected!' },
|
|
40
|
+
},
|
|
41
|
+
{ placement: 'top-center' }
|
|
42
|
+
);
|
|
43
|
+
promise(Promise.reject(), {
|
|
44
|
+
pending: { title: 'Promise is pending' },
|
|
45
|
+
success: { title: 'Promise resolved!' },
|
|
46
|
+
error: { title: 'Promise rejected!' },
|
|
47
|
+
});
|
|
48
|
+
notify({
|
|
49
|
+
title: 'Default',
|
|
50
|
+
variant: 'success',
|
|
51
|
+
placement: 'top-center',
|
|
52
|
+
});
|
|
53
|
+
notify({
|
|
54
|
+
title: 'This is a success',
|
|
55
|
+
});
|
|
56
|
+
success({
|
|
57
|
+
title: 'This is a success',
|
|
58
|
+
delay: 0,
|
|
59
|
+
});
|
|
60
|
+
warning({
|
|
61
|
+
title: 'This is a warning',
|
|
62
|
+
content: 'Cupcake ipsum dolor sit amet.',
|
|
63
|
+
delay: 0,
|
|
64
|
+
});
|
|
65
|
+
error({
|
|
66
|
+
title: 'This is an error',
|
|
67
|
+
content:
|
|
68
|
+
'Cupcake ipsum dolor sit amet. Cookie chocolate cake muffin chocolate bar powder cake chupa chups. Gummies chocolate cake cupcake chupa chups sesame snaps soufflé soufflé gingerbread blueie. Caramels chocolate bar soufflé sesame snaps tiramisu. Cookie muffin pie cake cupcake sweet.',
|
|
69
|
+
delay: 0,
|
|
70
|
+
closeButton: false,
|
|
71
|
+
});
|
|
72
|
+
info({
|
|
73
|
+
title: 'This is an info',
|
|
74
|
+
content:
|
|
75
|
+
'Cupcake ipsum dolor sit amet. Cookie chocolate cake muffin chocolate bar powder cake chupa chups.',
|
|
76
|
+
delay: 0,
|
|
77
|
+
});
|
|
78
|
+
loading({ title: 'Updating...' });
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
return <ToastContainer />;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
describe('useToast', () => {
|
|
85
|
+
beforeAll(() => {
|
|
86
|
+
jest.useFakeTimers();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('provides a promise method', async () => {
|
|
90
|
+
render(<InstantToast />);
|
|
91
|
+
|
|
92
|
+
act(() => {
|
|
93
|
+
jest.runAllTimers();
|
|
94
|
+
});
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.queryByText('Promise resolved!')).toBeInTheDocument();
|
|
97
|
+
expect(screen.queryByText('Promise rejected!')).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('provides an update method', async () => {
|
|
102
|
+
render(<InstantToast />);
|
|
103
|
+
|
|
104
|
+
act(() => {
|
|
105
|
+
jest.runAllTimers();
|
|
106
|
+
});
|
|
107
|
+
await waitFor(() => {
|
|
108
|
+
expect(screen.queryByText('Saved!')).toBeInTheDocument();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { toast } from 'react-toastify';
|
|
3
|
+
import { Toast } from '../toast';
|
|
4
|
+
import { useToastProps, useToastReturnType } from './types';
|
|
5
|
+
|
|
6
|
+
const notify: useToastReturnType['notify'] = (
|
|
7
|
+
{ content, closeButton, placement, title, variant = 'info', ...options },
|
|
8
|
+
props
|
|
9
|
+
) => {
|
|
10
|
+
return toast(
|
|
11
|
+
<Toast title={title} variant={variant} closeButton={closeButton} {...props}>
|
|
12
|
+
{content}
|
|
13
|
+
</Toast>,
|
|
14
|
+
{
|
|
15
|
+
type: variant === 'loading' ? 'default' : variant,
|
|
16
|
+
...(placement && { position: placement }),
|
|
17
|
+
...options,
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const update: useToastReturnType['update'] = (
|
|
23
|
+
id,
|
|
24
|
+
{ content, closeButton, placement, title, variant = 'info', ...options },
|
|
25
|
+
props
|
|
26
|
+
) => {
|
|
27
|
+
toast.update(id, {
|
|
28
|
+
render: ({ closeToast }) => (
|
|
29
|
+
<Toast
|
|
30
|
+
title={title}
|
|
31
|
+
variant={variant}
|
|
32
|
+
closeButton={closeButton}
|
|
33
|
+
closeToast={closeToast}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{content}
|
|
37
|
+
</Toast>
|
|
38
|
+
),
|
|
39
|
+
type: variant === 'loading' ? 'default' : variant,
|
|
40
|
+
...(placement && { position: placement }),
|
|
41
|
+
...options,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const promise: useToastReturnType['promise'] = (
|
|
46
|
+
promise,
|
|
47
|
+
{ pending, success, error },
|
|
48
|
+
{ closeButton, placement, ...options } = {},
|
|
49
|
+
props
|
|
50
|
+
) => {
|
|
51
|
+
toast.promise(promise, {
|
|
52
|
+
pending: {
|
|
53
|
+
render: ({ closeToast }) => (
|
|
54
|
+
<Toast
|
|
55
|
+
closeButton={closeButton}
|
|
56
|
+
title={pending.title}
|
|
57
|
+
variant="loading"
|
|
58
|
+
closeToast={closeToast}
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
{pending.content}
|
|
62
|
+
</Toast>
|
|
63
|
+
),
|
|
64
|
+
type: 'default',
|
|
65
|
+
...(placement && { position: placement }),
|
|
66
|
+
...options,
|
|
67
|
+
},
|
|
68
|
+
success: {
|
|
69
|
+
render: ({ closeToast }) => (
|
|
70
|
+
<Toast
|
|
71
|
+
closeButton={closeButton}
|
|
72
|
+
title={success.title}
|
|
73
|
+
variant="success"
|
|
74
|
+
closeToast={closeToast}
|
|
75
|
+
{...props}
|
|
76
|
+
>
|
|
77
|
+
{success.content}
|
|
78
|
+
</Toast>
|
|
79
|
+
),
|
|
80
|
+
type: 'success',
|
|
81
|
+
...(placement && { position: placement }),
|
|
82
|
+
...options,
|
|
83
|
+
},
|
|
84
|
+
error: {
|
|
85
|
+
render: ({ closeToast }) => (
|
|
86
|
+
<Toast
|
|
87
|
+
closeButton={closeButton}
|
|
88
|
+
title={error.title}
|
|
89
|
+
variant="error"
|
|
90
|
+
closeToast={closeToast}
|
|
91
|
+
{...props}
|
|
92
|
+
>
|
|
93
|
+
{error.content}
|
|
94
|
+
</Toast>
|
|
95
|
+
),
|
|
96
|
+
type: 'error',
|
|
97
|
+
...(placement && { position: placement }),
|
|
98
|
+
...options,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const useToast: useToastProps = () => {
|
|
104
|
+
return {
|
|
105
|
+
notify: notify,
|
|
106
|
+
clearWaitingQueue: toast.clearWaitingQueue,
|
|
107
|
+
dismiss: toast.dismiss,
|
|
108
|
+
done: toast.done,
|
|
109
|
+
error: (options, props) => {
|
|
110
|
+
return notify({ variant: 'error', ...options }, props);
|
|
111
|
+
},
|
|
112
|
+
info: (options, props) => {
|
|
113
|
+
return notify({ variant: 'info', ...options }, props);
|
|
114
|
+
},
|
|
115
|
+
isActive: toast.isActive,
|
|
116
|
+
loading: (options, props) => {
|
|
117
|
+
return notify({ variant: 'loading', ...options }, props);
|
|
118
|
+
},
|
|
119
|
+
promise: promise,
|
|
120
|
+
success: (options, props) => {
|
|
121
|
+
return notify({ variant: 'success', ...options }, props);
|
|
122
|
+
},
|
|
123
|
+
update: update,
|
|
124
|
+
warning: (options, props) => {
|
|
125
|
+
return notify({ variant: 'warning', ...options }, props);
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { mdiHelp } from '@redsift/icons';
|
|
3
|
+
import { Button, Flexbox, Icon, IconSize, Text } from '@redsift/design-system';
|
|
4
|
+
import { Tooltip, TooltipPlacement } from '.';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Popovers/Tooltip',
|
|
8
|
+
component: Tooltip,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const Uncontrolled = () => (
|
|
12
|
+
<Flexbox
|
|
13
|
+
flexDirection="row"
|
|
14
|
+
flexWrap="wrap"
|
|
15
|
+
justifyContent="center"
|
|
16
|
+
alignItems="center"
|
|
17
|
+
padding="32px"
|
|
18
|
+
style={{ backgroundColor: '#EFEFEF' }}
|
|
19
|
+
>
|
|
20
|
+
<Tooltip>
|
|
21
|
+
<Tooltip.Trigger>
|
|
22
|
+
<Button variant="secondary">Button</Button>
|
|
23
|
+
</Tooltip.Trigger>
|
|
24
|
+
<Tooltip.Content>My tooltip</Tooltip.Content>
|
|
25
|
+
</Tooltip>
|
|
26
|
+
<Tooltip>
|
|
27
|
+
<Tooltip.Trigger>My trigger</Tooltip.Trigger>
|
|
28
|
+
<Tooltip.Content>My tooltip</Tooltip.Content>
|
|
29
|
+
</Tooltip>
|
|
30
|
+
</Flexbox>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const Controlled = () => {
|
|
34
|
+
const id = '123';
|
|
35
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
36
|
+
const [isOpen2, setIsOpen2] = useState(false);
|
|
37
|
+
|
|
38
|
+
const handleOnOpen = (open: boolean) => {
|
|
39
|
+
setIsOpen(open);
|
|
40
|
+
console.log('#1', open);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleOnOpen2 = (open: boolean) => {
|
|
44
|
+
setIsOpen2(open);
|
|
45
|
+
console.log('#2', open);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Flexbox
|
|
50
|
+
flexDirection="row"
|
|
51
|
+
flexWrap="wrap"
|
|
52
|
+
justifyContent="center"
|
|
53
|
+
alignItems="center"
|
|
54
|
+
padding="32px"
|
|
55
|
+
style={{ backgroundColor: '#EFEFEF' }}
|
|
56
|
+
>
|
|
57
|
+
<Tooltip tooltipId={id} isOpen={isOpen} onOpen={handleOnOpen}>
|
|
58
|
+
<Tooltip.Trigger>
|
|
59
|
+
<Button variant="secondary">Button</Button>
|
|
60
|
+
</Tooltip.Trigger>
|
|
61
|
+
<Tooltip.Content>My tooltip</Tooltip.Content>
|
|
62
|
+
</Tooltip>
|
|
63
|
+
<Tooltip isOpen={isOpen2} onOpen={handleOnOpen2}>
|
|
64
|
+
<Tooltip.Trigger>My trigger</Tooltip.Trigger>
|
|
65
|
+
<Tooltip.Content>My tooltip</Tooltip.Content>
|
|
66
|
+
</Tooltip>
|
|
67
|
+
</Flexbox>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const AllPlacements = () => (
|
|
72
|
+
<Flexbox flexDirection="column" flexWrap="wrap" gap="32px" padding="48px" style={{ backgroundColor: '#EFEFEF' }}>
|
|
73
|
+
{['top', 'left', 'bottom', 'right'].map((side) => {
|
|
74
|
+
return (
|
|
75
|
+
<Flexbox key={side} flexDirection="row" flexWrap="wrap" justifyContent="space-evenly" alignItems="center">
|
|
76
|
+
{['start', '', 'end'].map((alignment) => {
|
|
77
|
+
return (
|
|
78
|
+
<div key={`${side}${alignment ? '-' : ''}${alignment}`} style={{ margin: '1em' }}>
|
|
79
|
+
<Tooltip isOpen placement={`${side}${alignment ? '-' : ''}${alignment}` as TooltipPlacement}>
|
|
80
|
+
<Tooltip.Trigger>
|
|
81
|
+
<Button variant="secondary">Button</Button>
|
|
82
|
+
</Tooltip.Trigger>
|
|
83
|
+
<Tooltip.Content>
|
|
84
|
+
<Text>{`Tooltip [${side}${alignment ? '-' : ''}${alignment}]`}</Text>
|
|
85
|
+
</Tooltip.Content>
|
|
86
|
+
</Tooltip>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
})}
|
|
90
|
+
</Flexbox>
|
|
91
|
+
);
|
|
92
|
+
})}
|
|
93
|
+
</Flexbox>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
export const InlineTooltip = () => (
|
|
97
|
+
<Flexbox flexDirection="column" gap="120px">
|
|
98
|
+
<p>
|
|
99
|
+
Some text with a
|
|
100
|
+
<Tooltip isOpen>
|
|
101
|
+
<Tooltip.Trigger>
|
|
102
|
+
<abbr style={{ borderBottom: '1px dotted', margin: '0 4px' }}>convoluted</abbr>
|
|
103
|
+
</Tooltip.Trigger>
|
|
104
|
+
<Tooltip.Content>
|
|
105
|
+
<Text>extremely complex and difficult to follow</Text>
|
|
106
|
+
</Tooltip.Content>
|
|
107
|
+
</Tooltip>
|
|
108
|
+
word in it.
|
|
109
|
+
</p>
|
|
110
|
+
<p>
|
|
111
|
+
And some text with a contextual help at the end
|
|
112
|
+
<Tooltip placement={TooltipPlacement.top} isOpen>
|
|
113
|
+
<Tooltip.Trigger>
|
|
114
|
+
<Icon icon={mdiHelp} size={IconSize.xsmall} style={{ display: 'inline-block', verticalAlign: 'super' }} />
|
|
115
|
+
</Tooltip.Trigger>
|
|
116
|
+
<Tooltip.Content>
|
|
117
|
+
<Text>A contextual help is help that is displayed in your product or web site</Text>
|
|
118
|
+
</Tooltip.Content>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
.
|
|
121
|
+
</p>
|
|
122
|
+
</Flexbox>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
export const EmptyTooltip = () => (
|
|
126
|
+
<Flexbox
|
|
127
|
+
flexDirection="row"
|
|
128
|
+
flexWrap="wrap"
|
|
129
|
+
justifyContent="center"
|
|
130
|
+
alignItems="center"
|
|
131
|
+
padding="32px"
|
|
132
|
+
style={{ backgroundColor: '#EFEFEF' }}
|
|
133
|
+
>
|
|
134
|
+
<Tooltip>
|
|
135
|
+
<Tooltip.Trigger>
|
|
136
|
+
<Button variant="secondary">Button</Button>
|
|
137
|
+
</Tooltip.Trigger>
|
|
138
|
+
</Tooltip>
|
|
139
|
+
</Flexbox>
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
export const TooltipOnDisabledButton = () => (
|
|
143
|
+
<Flexbox
|
|
144
|
+
flexDirection="row"
|
|
145
|
+
flexWrap="wrap"
|
|
146
|
+
justifyContent="center"
|
|
147
|
+
alignItems="center"
|
|
148
|
+
padding="32px"
|
|
149
|
+
style={{ backgroundColor: '#EFEFEF' }}
|
|
150
|
+
>
|
|
151
|
+
<Tooltip>
|
|
152
|
+
<Tooltip.Trigger>
|
|
153
|
+
<Button variant="secondary" isDisabled>
|
|
154
|
+
Disabled
|
|
155
|
+
</Button>
|
|
156
|
+
</Tooltip.Trigger>
|
|
157
|
+
<Tooltip.Content>
|
|
158
|
+
<Text margin="16px">
|
|
159
|
+
Cupcake ipsum dolor sit amet brownie jujubes topping sesame snaps. Liquorice marzipan jelly-o carrot cake
|
|
160
|
+
icing croissant carrot cake. Tart soufflé sweet roll halvah croissant wafer cotton candy. Candy halvah
|
|
161
|
+
marzipan bear claw donut.
|
|
162
|
+
</Text>
|
|
163
|
+
</Tooltip.Content>
|
|
164
|
+
</Tooltip>
|
|
165
|
+
</Flexbox>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
export const ContentCanBeClicked = () => (
|
|
169
|
+
<Flexbox
|
|
170
|
+
flexDirection="row"
|
|
171
|
+
flexWrap="wrap"
|
|
172
|
+
justifyContent="center"
|
|
173
|
+
alignItems="center"
|
|
174
|
+
padding="32px"
|
|
175
|
+
style={{ backgroundColor: '#EFEFEF' }}
|
|
176
|
+
>
|
|
177
|
+
<Tooltip>
|
|
178
|
+
<Tooltip.Trigger>
|
|
179
|
+
<Button variant="secondary">Button</Button>
|
|
180
|
+
</Tooltip.Trigger>
|
|
181
|
+
<Tooltip.Content>My tooltip{' '}
|
|
182
|
+
<a href="https://www.google.com" target="_blank" rel="noreferrer">
|
|
183
|
+
Click me
|
|
184
|
+
</a></Tooltip.Content>
|
|
185
|
+
</Tooltip>
|
|
186
|
+
<Tooltip>
|
|
187
|
+
<Tooltip.Trigger>My trigger</Tooltip.Trigger>
|
|
188
|
+
<Tooltip.Content>
|
|
189
|
+
My tooltip{' '}
|
|
190
|
+
<a href="https://www.google.com" target="_blank" rel="noreferrer">
|
|
191
|
+
Click me
|
|
192
|
+
</a>
|
|
193
|
+
</Tooltip.Content>
|
|
194
|
+
</Tooltip>
|
|
195
|
+
</Flexbox>
|
|
196
|
+
);
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
act,
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
screen,
|
|
7
|
+
waitFor,
|
|
8
|
+
} from '@testing-library/react';
|
|
9
|
+
|
|
10
|
+
import { Button } from '@redsift/design-system';
|
|
11
|
+
import { TooltipContent } from '../tooltip-content';
|
|
12
|
+
import { TooltipTrigger } from '../tooltip-trigger';
|
|
13
|
+
import { Tooltip } from '.';
|
|
14
|
+
|
|
15
|
+
describe('Tooltip', () => {
|
|
16
|
+
const onOpenSpy = jest.fn();
|
|
17
|
+
const realError = console.error;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
console.error = jest.fn();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
onOpenSpy.mockClear();
|
|
25
|
+
console.error = realError;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it.each`
|
|
29
|
+
Name | Component | props
|
|
30
|
+
${'TooltipTrigger'} | ${TooltipTrigger} | ${{}}
|
|
31
|
+
${'TooltipContent'} | ${TooltipContent} | ${{}}
|
|
32
|
+
`(
|
|
33
|
+
'$Name should throw error when not wrapped inside `Tooltip`',
|
|
34
|
+
function ({ Component, props }) {
|
|
35
|
+
expect(() => render(<Component {...props} />)).toThrow(
|
|
36
|
+
'Tooltip components must be wrapped in <Tooltip />'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// it.each`
|
|
42
|
+
// Name | Component | props
|
|
43
|
+
// ${'Controlled Tooltip'} | ${Tooltip} | ${{ onOpen: onOpenSpy, isOpen: false }}
|
|
44
|
+
// ${'Uncontrolled Tooltip'} | ${Tooltip} | ${{ onOpen: onOpenSpy, defaultOpen: false }}
|
|
45
|
+
// `(
|
|
46
|
+
// '$Name can be closed by default and then open',
|
|
47
|
+
// async function ({ Name, Component, props }) {
|
|
48
|
+
// const { getByText } = render(
|
|
49
|
+
// <Component delay={0} {...props}>
|
|
50
|
+
// <TooltipTrigger>
|
|
51
|
+
// <Button variant="secondary">Trigger</Button>
|
|
52
|
+
// </TooltipTrigger>
|
|
53
|
+
// <TooltipContent>Content</TooltipContent>
|
|
54
|
+
// </Component>
|
|
55
|
+
// );
|
|
56
|
+
|
|
57
|
+
// expect(screen.queryByText('Content')).not.toBeInTheDocument();
|
|
58
|
+
// expect(onOpenSpy).not.toHaveBeenCalled();
|
|
59
|
+
|
|
60
|
+
// const triggerButton = getByText('Trigger');
|
|
61
|
+
// fireEvent.mouseEnter(triggerButton);
|
|
62
|
+
|
|
63
|
+
// expect(onOpenSpy).toHaveBeenCalled();
|
|
64
|
+
// if (Name.includes('Uncontrolled')) {
|
|
65
|
+
// expect(getByText('Content')).not.toBeVisible();
|
|
66
|
+
// await act(async () => {});
|
|
67
|
+
// await waitFor(() => {
|
|
68
|
+
// expect(screen.queryByText('Content')).toBeInTheDocument();
|
|
69
|
+
// });
|
|
70
|
+
|
|
71
|
+
// expect(getByText('Content')).toBeVisible();
|
|
72
|
+
|
|
73
|
+
// fireEvent.mouseLeave(triggerButton);
|
|
74
|
+
|
|
75
|
+
// expect(screen.queryByText('Content')).not.toBeInTheDocument();
|
|
76
|
+
// expect(onOpenSpy).toHaveBeenCalled();
|
|
77
|
+
// }
|
|
78
|
+
// }
|
|
79
|
+
// );
|
|
80
|
+
|
|
81
|
+
it.each`
|
|
82
|
+
Name | Component | props
|
|
83
|
+
${'Controlled Tooltip'} | ${Tooltip} | ${{ onOpen: onOpenSpy, isOpen: true }}
|
|
84
|
+
${'Uncontrolled Tooltip'} | ${Tooltip} | ${{ onOpen: onOpenSpy, defaultOpen: true }}
|
|
85
|
+
`(
|
|
86
|
+
'$Name can be open by default and then closed',
|
|
87
|
+
async function ({ Name, Component, props }) {
|
|
88
|
+
const { getByText } = render(
|
|
89
|
+
<Component delay={0} {...props}>
|
|
90
|
+
<TooltipTrigger>
|
|
91
|
+
<Button variant="secondary">Trigger</Button>
|
|
92
|
+
</TooltipTrigger>
|
|
93
|
+
<TooltipContent>Content</TooltipContent>
|
|
94
|
+
</Component>
|
|
95
|
+
);
|
|
96
|
+
await act(async () => {});
|
|
97
|
+
await waitFor(() => {
|
|
98
|
+
expect(screen.queryByText('Content')).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(getByText('Content')).toBeVisible();
|
|
102
|
+
expect(onOpenSpy).not.toHaveBeenCalled();
|
|
103
|
+
|
|
104
|
+
fireEvent.keyDown(global.document, {
|
|
105
|
+
key: 'Escape',
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(onOpenSpy).toHaveBeenCalled();
|
|
109
|
+
if (Name.includes('Uncontrolled')) {
|
|
110
|
+
await act(async () => {});
|
|
111
|
+
await waitFor(() => {
|
|
112
|
+
expect(screen.queryByText('Content')).not.toBeInTheDocument();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(screen.queryByText('Content')).not.toBeInTheDocument();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
});
|