@onewelcome/react-lib-components 0.1.0-alpha → 0.1.1-alpha
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/dist/Button/IconButton.d.ts +1 -1
- package/dist/Form/Fieldset/Fieldset.d.ts +6 -4
- package/dist/Form/FormControl/FormControl.d.ts +2 -1
- package/dist/Form/Wrapper/SelectWrapper/SelectWrapper.d.ts +2 -1
- package/dist/{BaseModal → Notifications/BaseModal}/BaseModal.d.ts +4 -2
- package/dist/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.d.ts +0 -0
- package/dist/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.d.ts +0 -0
- package/dist/{BaseModal → Notifications/BaseModal}/BaseModalContext.d.ts +0 -0
- package/dist/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.d.ts +1 -1
- package/dist/{Dialog → Notifications/Dialog}/Dialog.d.ts +4 -3
- package/dist/{Dialog → Notifications/Dialog}/DialogActions/DialogActions.d.ts +0 -0
- package/dist/{Dialog → Notifications/Dialog}/DialogTitle/DialogTitle.d.ts +0 -0
- package/dist/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.d.ts +12 -0
- package/dist/Notifications/DiscardChangesModal/DiscardChangesModal.d.ts +11 -0
- package/dist/{Modal → Notifications/Modal}/Modal.d.ts +0 -0
- package/dist/{Modal → Notifications/Modal}/ModalActions/ModalActions.d.ts +0 -0
- package/dist/{Modal → Notifications/Modal}/ModalContent/ModalContent.d.ts +0 -0
- package/dist/{Modal → Notifications/Modal}/ModalHeader/ModalHeader.d.ts +0 -0
- package/dist/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.d.ts +0 -0
- package/dist/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.d.ts +0 -0
- package/dist/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.d.ts +1 -1
- package/dist/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarStateProvider.d.ts +0 -0
- package/dist/{Snackbar → Notifications/Snackbar}/interfaces.d.ts +0 -0
- package/dist/{Snackbar → Notifications/Snackbar}/useSnackbar.d.ts +0 -0
- package/dist/Tiles/Tile.d.ts +4 -5
- package/dist/index.d.ts +8 -7
- package/dist/react-lib-components.cjs.development.js +226 -125
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +226 -126
- package/dist/react-lib-components.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/Button/IconButton.tsx +8 -4
- package/src/Form/Checkbox/Checkbox.module.scss +4 -0
- package/src/Form/Checkbox/Checkbox.tsx +11 -6
- package/src/Form/Fieldset/Fieldset.module.scss +11 -1
- package/src/Form/Fieldset/Fieldset.test.tsx +2 -2
- package/src/Form/Fieldset/Fieldset.tsx +22 -10
- package/src/Form/FormControl/FormControl.tsx +3 -0
- package/src/Form/Radio/Radio.module.scss +4 -0
- package/src/Form/Radio/Radio.tsx +12 -2
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.test.tsx +1 -1
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.tsx +1 -1
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.test.tsx +1 -1
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.tsx +1 -1
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +2 -1
- package/src/{BaseModal → Notifications/BaseModal}/BaseModal.module.scss +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModal.test.tsx +8 -15
- package/src/{BaseModal → Notifications/BaseModal}/BaseModal.tsx +11 -24
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.module.scss +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.test.tsx +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.tsx +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.module.scss +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.test.tsx +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.tsx +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalContext.ts +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.module.scss +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.test.tsx +0 -0
- package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.tsx +6 -6
- package/src/{Dialog → Notifications/Dialog}/Dialog.module.scss +0 -0
- package/src/{Dialog → Notifications/Dialog}/Dialog.test.tsx +13 -16
- package/src/{Dialog → Notifications/Dialog}/Dialog.tsx +17 -6
- package/src/{Dialog → Notifications/Dialog}/DialogActions/DialogActions.module.scss +0 -0
- package/src/{Dialog → Notifications/Dialog}/DialogActions/DialogActions.test.tsx +0 -0
- package/src/{Dialog → Notifications/Dialog}/DialogActions/DialogActions.tsx +0 -0
- package/src/{Dialog → Notifications/Dialog}/DialogTitle/DialogTitle.module.scss +0 -0
- package/src/{Dialog → Notifications/Dialog}/DialogTitle/DialogTitle.test.tsx +0 -0
- package/src/{Dialog → Notifications/Dialog}/DialogTitle/DialogTitle.tsx +3 -3
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +55 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +48 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +111 -0
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +56 -0
- package/src/{Modal → Notifications/Modal}/Modal.test.tsx +0 -0
- package/src/{Modal → Notifications/Modal}/Modal.tsx +0 -0
- package/src/{Modal → Notifications/Modal}/ModalActions/ModalActions.tsx +0 -0
- package/src/{Modal → Notifications/Modal}/ModalContent/ModalContent.tsx +0 -0
- package/src/{Modal → Notifications/Modal}/ModalHeader/ModalHeader.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.module.scss +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.test.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.module.scss +1 -1
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.test.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.tsx +5 -6
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.test.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.tsx +2 -2
- package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarStateProvider.tsx +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/interfaces.ts +0 -0
- package/src/{Snackbar → Notifications/Snackbar}/useSnackbar.ts +0 -0
- package/src/Popover/Popover.test.tsx +3 -3
- package/src/Tiles/Tile.module.scss +1 -1
- package/src/Tiles/Tile.test.tsx +21 -11
- package/src/Tiles/Tile.tsx +52 -15
- package/src/Tiles/Tiles.test.tsx +11 -9
- package/src/Tiles/Tiles.tsx +3 -3
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +3 -3
- package/src/Wizard/Wizard.tsx +2 -2
- package/src/Wizard/WizardActions/WizardActions.tsx +3 -3
- package/src/hooks/usePosition.test.tsx +3 -3
- package/src/index.ts +8 -7
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Typography } from '
|
|
2
|
+
import { Typography } from '../../../Typography/Typography';
|
|
3
3
|
import classes from './DialogTitle.module.scss';
|
|
4
4
|
|
|
5
5
|
export interface Props {
|
|
@@ -9,10 +9,10 @@ export interface Props {
|
|
|
9
9
|
|
|
10
10
|
export const DialogTitle = ({ id, title }: Props) => {
|
|
11
11
|
return (
|
|
12
|
-
<
|
|
12
|
+
<div className={classes['header']}>
|
|
13
13
|
<Typography id={id} className={classes['title']} tag="h1" variant="h4">
|
|
14
14
|
{title}
|
|
15
15
|
</Typography>
|
|
16
|
-
</
|
|
16
|
+
</div>
|
|
17
17
|
);
|
|
18
18
|
};
|
package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DiscardChangesDialog, Props } from './DiscardChangesDialog';
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
|
|
6
|
+
const defaultParams: Props = {
|
|
7
|
+
open: true,
|
|
8
|
+
onKeepEditing: jest.fn(),
|
|
9
|
+
onDiscardChanges: jest.fn(),
|
|
10
|
+
discardChangesButtonLabel: 'Discard Changes',
|
|
11
|
+
keepEditingButtonLabel: 'Keep Editing',
|
|
12
|
+
contentLabel: 'Content',
|
|
13
|
+
titleLabel: 'Unsaved changes',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const createDiscardChangesDialog = (params?: (defaultParams: Props) => Props) => {
|
|
17
|
+
let parameters: Props = defaultParams;
|
|
18
|
+
if (params) {
|
|
19
|
+
parameters = params(defaultParams);
|
|
20
|
+
}
|
|
21
|
+
const queries = render(
|
|
22
|
+
<DiscardChangesDialog {...parameters} data-testid="DiscardChangesDialog"></DiscardChangesDialog>
|
|
23
|
+
);
|
|
24
|
+
const discardChangesDialog = queries.getByTestId('DiscardChangesDialog');
|
|
25
|
+
const discardChangesBtn = queries.getByRole('button', {
|
|
26
|
+
name: defaultParams.discardChangesButtonLabel,
|
|
27
|
+
});
|
|
28
|
+
const keepEditingBtn = queries.getByRole('button', {
|
|
29
|
+
name: defaultParams.keepEditingButtonLabel,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
...queries,
|
|
34
|
+
discardChangesDialog,
|
|
35
|
+
discardChangesBtn,
|
|
36
|
+
keepEditingBtn,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
describe('DiscardChangesDialog should render', () => {
|
|
41
|
+
it('renders without crashing', () => {
|
|
42
|
+
const { discardChangesDialog, discardChangesBtn, keepEditingBtn } =
|
|
43
|
+
createDiscardChangesDialog();
|
|
44
|
+
|
|
45
|
+
expect(discardChangesDialog).toBeDefined();
|
|
46
|
+
expect(discardChangesDialog).toHaveTextContent(defaultParams.contentLabel);
|
|
47
|
+
expect(discardChangesDialog).toHaveTextContent(defaultParams.titleLabel);
|
|
48
|
+
|
|
49
|
+
userEvent.click(discardChangesBtn);
|
|
50
|
+
expect(defaultParams.onDiscardChanges).toBeCalledTimes(1);
|
|
51
|
+
|
|
52
|
+
userEvent.click(keepEditingBtn);
|
|
53
|
+
expect(defaultParams.onKeepEditing).toBeCalledTimes(1);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Dialog } from '../../Dialog/Dialog';
|
|
3
|
+
import { HTMLProps } from '../../../interfaces';
|
|
4
|
+
import { Typography } from '../../../Typography/Typography';
|
|
5
|
+
|
|
6
|
+
export interface Props extends Omit<HTMLProps<HTMLDivElement>, 'children'> {
|
|
7
|
+
open: boolean;
|
|
8
|
+
discardChangesButtonLabel: string;
|
|
9
|
+
keepEditingButtonLabel: string;
|
|
10
|
+
contentLabel: string;
|
|
11
|
+
titleLabel: string;
|
|
12
|
+
onKeepEditing: () => void;
|
|
13
|
+
onDiscardChanges: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const DiscardChangesDialog = ({
|
|
17
|
+
open,
|
|
18
|
+
onKeepEditing,
|
|
19
|
+
onDiscardChanges,
|
|
20
|
+
discardChangesButtonLabel,
|
|
21
|
+
keepEditingButtonLabel,
|
|
22
|
+
contentLabel,
|
|
23
|
+
titleLabel,
|
|
24
|
+
...rest
|
|
25
|
+
}: Props) => {
|
|
26
|
+
return (
|
|
27
|
+
<Dialog
|
|
28
|
+
{...rest}
|
|
29
|
+
open={open}
|
|
30
|
+
alignActions="left"
|
|
31
|
+
title={titleLabel}
|
|
32
|
+
onClose={onKeepEditing}
|
|
33
|
+
primaryAction={{
|
|
34
|
+
label: discardChangesButtonLabel,
|
|
35
|
+
onClick: onDiscardChanges,
|
|
36
|
+
}}
|
|
37
|
+
secondaryAction={{
|
|
38
|
+
label: keepEditingButtonLabel,
|
|
39
|
+
onClick: onKeepEditing,
|
|
40
|
+
}}
|
|
41
|
+
disableEscapeKeyDown={false}
|
|
42
|
+
>
|
|
43
|
+
<Typography variant="body" spacing={{ margin: 0 }}>
|
|
44
|
+
{contentLabel}
|
|
45
|
+
</Typography>
|
|
46
|
+
</Dialog>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DiscardChangesModal, Props } from './DiscardChangesModal';
|
|
3
|
+
import { findByTestId, getAllByRole, render, waitFor } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
|
|
6
|
+
const defaultParams: Props = {
|
|
7
|
+
id: 'modal',
|
|
8
|
+
open: true,
|
|
9
|
+
hasUnsavedChanges: jest.fn(),
|
|
10
|
+
onClose: jest.fn(),
|
|
11
|
+
headerProps: {
|
|
12
|
+
title: 'Header',
|
|
13
|
+
},
|
|
14
|
+
discardChangedDialogProps: {
|
|
15
|
+
'data-testid': 'discardChangesDialog',
|
|
16
|
+
discardChangesButtonLabel: 'Discard',
|
|
17
|
+
keepEditingButtonLabel: 'Keep editing',
|
|
18
|
+
contentLabel: 'Unsaved changes',
|
|
19
|
+
titleLabel: 'Dialog',
|
|
20
|
+
},
|
|
21
|
+
children: <span>children</span>,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const createDiscardChangesModal = (params?: (defaultParams: Props) => Props) => {
|
|
25
|
+
let parameters: Props = defaultParams;
|
|
26
|
+
if (params) {
|
|
27
|
+
parameters = params(defaultParams);
|
|
28
|
+
}
|
|
29
|
+
const queries = render(<DiscardChangesModal {...parameters} data-testid="discardChangesModal" />);
|
|
30
|
+
const discardChangesModal = queries.getByTestId('discardChangesModal');
|
|
31
|
+
const closeBtn = queries.getByRole('button', { name: 'close modal' });
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
...queries,
|
|
35
|
+
discardChangesModal,
|
|
36
|
+
closeBtn,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getDiscardChangesButtons = (container: HTMLElement) =>
|
|
41
|
+
getAllByRole(container, 'button', {
|
|
42
|
+
name: new RegExp(
|
|
43
|
+
`(${defaultParams.discardChangedDialogProps.discardChangesButtonLabel}|${defaultParams.discardChangedDialogProps.keepEditingButtonLabel})`
|
|
44
|
+
),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const findDiscardChangesDialog = (container: HTMLElement) =>
|
|
48
|
+
findByTestId(container, 'discardChangesDialog');
|
|
49
|
+
|
|
50
|
+
describe('DiscardChangesModal should render', () => {
|
|
51
|
+
it('renders without crashing', () => {
|
|
52
|
+
const { discardChangesModal, container } = createDiscardChangesModal();
|
|
53
|
+
|
|
54
|
+
expect(discardChangesModal).toBeDefined();
|
|
55
|
+
expect(discardChangesModal).toHaveTextContent('children');
|
|
56
|
+
expect(discardChangesModal).toHaveTextContent(defaultParams.headerProps.title);
|
|
57
|
+
expect(container).not.toHaveTextContent(defaultParams.discardChangedDialogProps.titleLabel);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('clicking on close button without making any changes close the modal', () => {
|
|
61
|
+
(
|
|
62
|
+
defaultParams.hasUnsavedChanges as jest.MockedFunction<typeof defaultParams.hasUnsavedChanges>
|
|
63
|
+
).mockReturnValue(false);
|
|
64
|
+
const { closeBtn } = createDiscardChangesModal();
|
|
65
|
+
|
|
66
|
+
userEvent.click(closeBtn);
|
|
67
|
+
expect(defaultParams.onClose).toBeCalledTimes(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('DiscardChangesModal should show DiscardChangesDialog', () => {
|
|
72
|
+
it('showing DiscardChangesDialog and clicking on `keep editing` button', async () => {
|
|
73
|
+
(
|
|
74
|
+
defaultParams.hasUnsavedChanges as jest.MockedFunction<typeof defaultParams.hasUnsavedChanges>
|
|
75
|
+
).mockReturnValue(true);
|
|
76
|
+
const { closeBtn } = createDiscardChangesModal();
|
|
77
|
+
const container = document.body;
|
|
78
|
+
expect(defaultParams.onClose).not.toBeCalled();
|
|
79
|
+
|
|
80
|
+
userEvent.click(closeBtn);
|
|
81
|
+
|
|
82
|
+
expect(defaultParams.onClose).not.toBeCalled();
|
|
83
|
+
await findDiscardChangesDialog(container);
|
|
84
|
+
const [_, keepEditingBtn] = getDiscardChangesButtons(container);
|
|
85
|
+
expect(container).toHaveTextContent(defaultParams.discardChangedDialogProps.titleLabel);
|
|
86
|
+
expect(container).toHaveTextContent(defaultParams.discardChangedDialogProps.contentLabel);
|
|
87
|
+
|
|
88
|
+
userEvent.click(keepEditingBtn);
|
|
89
|
+
expect(defaultParams.onClose).not.toBeCalled();
|
|
90
|
+
await waitFor(() =>
|
|
91
|
+
expect(container).not.toHaveTextContent(defaultParams.discardChangedDialogProps.titleLabel)
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('showing DiscardChangesDialog and clicking on `discard` button', async () => {
|
|
96
|
+
(
|
|
97
|
+
defaultParams.hasUnsavedChanges as jest.MockedFunction<typeof defaultParams.hasUnsavedChanges>
|
|
98
|
+
).mockReturnValue(true);
|
|
99
|
+
const { closeBtn } = createDiscardChangesModal();
|
|
100
|
+
const container = document.body;
|
|
101
|
+
|
|
102
|
+
userEvent.click(closeBtn);
|
|
103
|
+
|
|
104
|
+
await findDiscardChangesDialog(container);
|
|
105
|
+
const [discardBtn] = getDiscardChangesButtons(container);
|
|
106
|
+
expect(container).toHaveTextContent(defaultParams.discardChangedDialogProps.titleLabel);
|
|
107
|
+
|
|
108
|
+
userEvent.click(discardBtn);
|
|
109
|
+
expect(defaultParams.onClose).toBeCalled();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { Fragment, useState } from 'react';
|
|
2
|
+
import { Modal, Props as ModalProps } from '../Modal/Modal';
|
|
3
|
+
import { ModalHeader, Props as ModalHeaderProps } from '../Modal/ModalHeader/ModalHeader';
|
|
4
|
+
import {
|
|
5
|
+
DiscardChangesDialog,
|
|
6
|
+
Props as DiscardChangesDialogProps,
|
|
7
|
+
} from './DiscardChangesDialog/DiscardChangesDialog';
|
|
8
|
+
|
|
9
|
+
export interface Props extends Omit<ModalProps, 'onClose'> {
|
|
10
|
+
hasUnsavedChanges: () => boolean;
|
|
11
|
+
onClose: (event?: React.MouseEvent<HTMLElement>) => unknown;
|
|
12
|
+
headerProps: Omit<ModalHeaderProps, 'onClose' | 'id'>;
|
|
13
|
+
discardChangedDialogProps: Omit<
|
|
14
|
+
DiscardChangesDialogProps,
|
|
15
|
+
'open' | 'onKeepEditing' | 'onDiscardChanges'
|
|
16
|
+
>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const DiscardChangesModal = ({
|
|
20
|
+
id,
|
|
21
|
+
onClose,
|
|
22
|
+
children,
|
|
23
|
+
hasUnsavedChanges,
|
|
24
|
+
headerProps,
|
|
25
|
+
discardChangedDialogProps,
|
|
26
|
+
...rest
|
|
27
|
+
}: Props) => {
|
|
28
|
+
const [openDiscardChangesDialog, setOpenDiscardChangesDialog] = useState(false);
|
|
29
|
+
|
|
30
|
+
const onCloseWrapper = () =>
|
|
31
|
+
hasUnsavedChanges() ? setOpenDiscardChangesDialog(true) : onClose();
|
|
32
|
+
|
|
33
|
+
const onDialogKeepEditing = () => {
|
|
34
|
+
setOpenDiscardChangesDialog(false);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const onDialogDiscardChanges = () => {
|
|
38
|
+
setOpenDiscardChangesDialog(false);
|
|
39
|
+
onClose();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Fragment>
|
|
44
|
+
<Modal id={id} onClose={onCloseWrapper} {...rest}>
|
|
45
|
+
<ModalHeader {...headerProps} id={`${id}-label`} onClose={onCloseWrapper} />
|
|
46
|
+
{children}
|
|
47
|
+
</Modal>
|
|
48
|
+
<DiscardChangesDialog
|
|
49
|
+
{...discardChangedDialogProps}
|
|
50
|
+
open={openDiscardChangesDialog}
|
|
51
|
+
onKeepEditing={onDialogKeepEditing}
|
|
52
|
+
onDiscardChanges={onDialogDiscardChanges}
|
|
53
|
+
/>
|
|
54
|
+
</Fragment>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.module.scss
RENAMED
|
File without changes
|
package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.test.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { IconButton } from '
|
|
3
|
-
import { Icon, Icons } from '
|
|
2
|
+
import { IconButton } from '../../../Button/IconButton';
|
|
3
|
+
import { Icon, Icons } from '../../../Icon/Icon';
|
|
4
4
|
import { Variant, Actions } from '../interfaces';
|
|
5
5
|
import classes from './SnackbarItem.module.scss';
|
|
6
|
-
import readyclasses from '
|
|
7
|
-
import { useAnimation } from '
|
|
8
|
-
import { Typography } from '
|
|
6
|
+
import readyclasses from '../../../readyclasses.module.scss';
|
|
7
|
+
import { useAnimation } from '../../../hooks/useAnimation';
|
|
8
|
+
import { Typography } from '../../../Typography/Typography';
|
|
9
9
|
|
|
10
10
|
const textColor = 'var(--snackbar-text-color)';
|
|
11
11
|
|
|
@@ -92,7 +92,6 @@ export const SnackbarItem = ({
|
|
|
92
92
|
<Icon icon={Icons.Times} color={textColor} />
|
|
93
93
|
</IconButton>
|
|
94
94
|
</div>
|
|
95
|
-
{/* @TODO: change it to Typography*/}
|
|
96
95
|
{!!content && (
|
|
97
96
|
<Typography className={classes['content']} variant="body">
|
|
98
97
|
{content}
|
|
File without changes
|
|
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
|
|
|
3
3
|
import { SnackbarContextProvider } from './SnackbarStateProvider';
|
|
4
4
|
import { Actions, SnackbarOptionsProps, Variant } from '../interfaces';
|
|
5
5
|
import { Placement, SnackbarContainer } from '../SnackbarContainer/SnackbarContainer';
|
|
6
|
-
import { generateID } from '
|
|
6
|
+
import { generateID } from '../../../util/helper';
|
|
7
7
|
import { SnackbarItem } from '../SnackbarItem/SnackbarItem';
|
|
8
8
|
|
|
9
9
|
/** Short msg is when only title is provided. Long one when content or/and actions are provided (or type is error). */
|
|
@@ -14,7 +14,7 @@ interface Duration {
|
|
|
14
14
|
|
|
15
15
|
export interface Props {
|
|
16
16
|
closeButtonTitle: string;
|
|
17
|
-
children?: ReactNode
|
|
17
|
+
children?: ReactNode;
|
|
18
18
|
placement?: Placement;
|
|
19
19
|
stackSize?: number;
|
|
20
20
|
domRoot?: HTMLElement;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef } from 'react';
|
|
1
|
+
import React, { Fragment, useRef } from 'react';
|
|
2
2
|
import { Popover, Props } from './Popover';
|
|
3
3
|
import { render } from '@testing-library/react';
|
|
4
4
|
import { usePosition } from '../hooks/usePosition';
|
|
@@ -32,7 +32,7 @@ const createPopover = (params?: (defaultParams: Props) => Props) => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
|
-
|
|
35
|
+
<Fragment>
|
|
36
36
|
<button data-testid="button" onClick={calculatePosition} ref={relativeElement}>
|
|
37
37
|
Test
|
|
38
38
|
</button>
|
|
@@ -44,7 +44,7 @@ const createPopover = (params?: (defaultParams: Props) => Props) => {
|
|
|
44
44
|
>
|
|
45
45
|
Test
|
|
46
46
|
</Popover>
|
|
47
|
-
|
|
47
|
+
</Fragment>
|
|
48
48
|
);
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
padding: 0 0 2rem;
|
|
8
8
|
background-color: #fff;
|
|
9
9
|
transition: box-shadow 0.2s ease-in-out;
|
|
10
|
+
font-family: var(--font-family);
|
|
10
11
|
|
|
11
12
|
&:hover {
|
|
12
13
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.29);
|
|
@@ -14,7 +15,6 @@
|
|
|
14
15
|
|
|
15
16
|
header {
|
|
16
17
|
display: flex;
|
|
17
|
-
justify-content: space-between;
|
|
18
18
|
align-items: center;
|
|
19
19
|
|
|
20
20
|
.icon {
|
package/src/Tiles/Tile.test.tsx
CHANGED
|
@@ -10,7 +10,6 @@ import userEvent from '@testing-library/user-event';
|
|
|
10
10
|
const onShow = jest.fn();
|
|
11
11
|
const onClose = jest.fn();
|
|
12
12
|
const contextMenuItemOnClick = jest.fn();
|
|
13
|
-
const iconClick = jest.fn();
|
|
14
13
|
|
|
15
14
|
const contextMenu = (
|
|
16
15
|
<ContextMenu
|
|
@@ -38,8 +37,8 @@ const contextMenu = (
|
|
|
38
37
|
|
|
39
38
|
const defaultParams: Props = {
|
|
40
39
|
title: 'tile',
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
enabled: true,
|
|
41
|
+
tileAction: contextMenu,
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
const createTile = (params?: (defaultParams: Props) => Props) => {
|
|
@@ -54,25 +53,36 @@ const createTile = (params?: (defaultParams: Props) => Props) => {
|
|
|
54
53
|
);
|
|
55
54
|
const tile = queries.getByTestId('tile');
|
|
56
55
|
const menutrigger = queries.getByTestId('contextmenu-trigger');
|
|
57
|
-
const icon = queries.getByTestId('icon');
|
|
58
56
|
|
|
59
57
|
return {
|
|
60
58
|
...queries,
|
|
61
59
|
tile,
|
|
62
60
|
menutrigger,
|
|
63
|
-
icon,
|
|
64
61
|
};
|
|
65
62
|
};
|
|
66
63
|
|
|
67
64
|
describe('Tile should render', () => {
|
|
68
|
-
it('renders without crashing', () => {
|
|
69
|
-
const { tile
|
|
65
|
+
it('renders without crashing and enabled', () => {
|
|
66
|
+
const { tile } = createTile();
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
expect(iconClick).toHaveBeenCalled();
|
|
68
|
+
expect(tile.querySelector('.icon-checkmark')).toBeTruthy();
|
|
69
|
+
expect(tile.querySelector('.icon-forbidden')).toBeFalsy();
|
|
74
70
|
expect(tile).toBeDefined();
|
|
75
71
|
});
|
|
72
|
+
|
|
73
|
+
it('renders disabled', () => {
|
|
74
|
+
const { tile } = createTile((defaultParams) => ({ ...defaultParams, enabled: false }));
|
|
75
|
+
|
|
76
|
+
expect(tile.querySelector('.icon-checkmark')).toBeFalsy();
|
|
77
|
+
expect(tile.querySelector('.icon-forbidden')).toBeTruthy();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('renders no status', () => {
|
|
81
|
+
const { tile } = createTile((defaultParams) => ({ ...defaultParams, enabled: undefined }));
|
|
82
|
+
|
|
83
|
+
expect(tile.querySelector('.icon-checkmark')).toBeFalsy();
|
|
84
|
+
expect(tile.querySelector('.icon-forbidden')).toBeFalsy();
|
|
85
|
+
});
|
|
76
86
|
});
|
|
77
87
|
|
|
78
88
|
describe("should throw errors since we don't pass props", () => {
|
|
@@ -85,7 +95,7 @@ describe("should throw errors since we don't pass props", () => {
|
|
|
85
95
|
|
|
86
96
|
try {
|
|
87
97
|
// @ts-ignore: mandatory props (test for non-typescript react projects)
|
|
88
|
-
render(<Tile imageProps={{ src: 'test'
|
|
98
|
+
render(<Tile imageProps={{ src: 'test' }} />);
|
|
89
99
|
} catch (e: any) {
|
|
90
100
|
actual = e.message;
|
|
91
101
|
}
|
package/src/Tiles/Tile.tsx
CHANGED
|
@@ -1,48 +1,85 @@
|
|
|
1
|
-
import React, { HTMLProps, ReactElement } from 'react';
|
|
2
|
-
import { Icon, Icons
|
|
1
|
+
import React, { HTMLProps, ReactElement, useState } from 'react';
|
|
2
|
+
import { Icon, Icons } from '../Icon/Icon';
|
|
3
3
|
import classes from './Tile.module.scss';
|
|
4
|
+
import readyClasses from '../readyclasses.module.scss';
|
|
4
5
|
|
|
5
6
|
import { Props as ContextMenuProps } from '../ContextMenu/ContextMenu';
|
|
7
|
+
import { generateID } from '../util/helper';
|
|
8
|
+
import { Props as IconButtonProps } from '../Button/IconButton';
|
|
6
9
|
|
|
7
10
|
interface ImageProps {
|
|
8
11
|
src: string;
|
|
9
|
-
alt: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export interface Props extends Omit<HTMLProps<HTMLDivElement>, 'contextMenu'> {
|
|
13
15
|
title: string;
|
|
14
16
|
imageProps?: ImageProps;
|
|
15
|
-
|
|
17
|
+
enabled?: boolean;
|
|
16
18
|
loading?: boolean;
|
|
17
|
-
|
|
19
|
+
tileAction?: ReactElement<ContextMenuProps> | ReactElement<IconButtonProps>;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export const Tile = ({
|
|
21
23
|
title,
|
|
22
24
|
imageProps,
|
|
23
|
-
|
|
25
|
+
enabled,
|
|
24
26
|
className,
|
|
25
27
|
loading,
|
|
26
|
-
|
|
28
|
+
tileAction,
|
|
27
29
|
...rest
|
|
28
30
|
}: Props) => {
|
|
31
|
+
const [tileDescriptionID] = useState(generateID(20));
|
|
32
|
+
|
|
29
33
|
if (!title) {
|
|
30
34
|
throw new Error('Please make sure to pass a title prop to your Tile component.');
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
const statusMessage = () => {
|
|
38
|
+
if (enabled) {
|
|
39
|
+
return 'Status: enabled';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return 'Status: disabled';
|
|
43
|
+
};
|
|
44
|
+
|
|
33
45
|
return (
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
<article
|
|
47
|
+
tabIndex={0}
|
|
48
|
+
aria-labelledby={tileDescriptionID}
|
|
49
|
+
{...rest}
|
|
50
|
+
className={`${classes['tile']} ${loading ? classes['loading'] : ''}`}
|
|
51
|
+
>
|
|
52
|
+
<header style={{ justifyContent: enabled === undefined ? 'flex-end' : 'space-between' }}>
|
|
53
|
+
{enabled === true && (
|
|
54
|
+
<Icon
|
|
55
|
+
color="var(--success)"
|
|
56
|
+
icon={Icons.Checkmark}
|
|
57
|
+
className={`${classes['icon']} ${className ?? ''}`}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
{enabled === false && (
|
|
61
|
+
<Icon
|
|
62
|
+
color="var(--greyed-out)"
|
|
63
|
+
icon={Icons.Forbidden}
|
|
64
|
+
className={`${classes['icon']} ${className ?? ''}`}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
{enabled !== undefined && (
|
|
68
|
+
<span id={tileDescriptionID} className={readyClasses['sr-only']}>
|
|
69
|
+
{`${title}. ${statusMessage()}`}
|
|
70
|
+
</span>
|
|
71
|
+
)}
|
|
72
|
+
{tileAction ?? null}
|
|
38
73
|
</header>
|
|
39
74
|
<div className={classes['content']}>
|
|
40
|
-
{imageProps && imageProps.src
|
|
41
|
-
<figure className={classes['image']}>{!loading && <img {...imageProps} />}</figure>
|
|
75
|
+
{imageProps && imageProps.src.length > 0 && (
|
|
76
|
+
<figure className={classes['image']}>{!loading && <img {...imageProps} alt="" />}</figure>
|
|
77
|
+
)}
|
|
78
|
+
{(!imageProps || imageProps.src.length === 0) && (
|
|
79
|
+
<Icon className={classes['placeholder']} icon={Icons.Image} />
|
|
42
80
|
)}
|
|
43
|
-
{!imageProps && <Icon className={classes['placeholder']} icon={Icons.Image} />}
|
|
44
81
|
<span className={classes['title']}>{title}</span>
|
|
45
82
|
</div>
|
|
46
|
-
</
|
|
83
|
+
</article>
|
|
47
84
|
);
|
|
48
85
|
};
|
package/src/Tiles/Tiles.test.tsx
CHANGED
|
@@ -34,6 +34,12 @@ const contextMenu = (
|
|
|
34
34
|
</ContextMenu>
|
|
35
35
|
);
|
|
36
36
|
|
|
37
|
+
const addToFavoriteButton = (
|
|
38
|
+
<IconButton title="Add to favorite">
|
|
39
|
+
<Icon icon={Icons.Star} />
|
|
40
|
+
</IconButton>
|
|
41
|
+
);
|
|
42
|
+
|
|
37
43
|
const defaultParams: Props = {
|
|
38
44
|
children: [
|
|
39
45
|
<Tile
|
|
@@ -42,10 +48,9 @@ const defaultParams: Props = {
|
|
|
42
48
|
title="Tile1"
|
|
43
49
|
imageProps={{
|
|
44
50
|
src: 'https://www.onegini.com/hubfs/OneWelcome_Beeldmerk.svg',
|
|
45
|
-
alt: 'OneWelcome logo',
|
|
46
51
|
}}
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
enabled={true}
|
|
53
|
+
tileAction={contextMenu}
|
|
49
54
|
/>,
|
|
50
55
|
<Tile
|
|
51
56
|
data-testid="tile"
|
|
@@ -53,10 +58,9 @@ const defaultParams: Props = {
|
|
|
53
58
|
title="Tile2"
|
|
54
59
|
imageProps={{
|
|
55
60
|
src: 'https://www.onegini.com/hubfs/OneWelcome_Beeldmerk.svg',
|
|
56
|
-
alt: 'OneWelcome logo',
|
|
57
61
|
}}
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
enabled={false}
|
|
63
|
+
tileAction={addToFavoriteButton}
|
|
60
64
|
/>,
|
|
61
65
|
<Tile
|
|
62
66
|
data-testid="tile"
|
|
@@ -64,10 +68,8 @@ const defaultParams: Props = {
|
|
|
64
68
|
title="Tile3"
|
|
65
69
|
imageProps={{
|
|
66
70
|
src: 'https://www.onegini.com/hubfs/OneWelcome_Beeldmerk.svg',
|
|
67
|
-
alt: 'OneWelcome logo',
|
|
68
71
|
}}
|
|
69
|
-
|
|
70
|
-
menu={contextMenu}
|
|
72
|
+
tileAction={contextMenu}
|
|
71
73
|
/>,
|
|
72
74
|
],
|
|
73
75
|
className: 'example-classname',
|
package/src/Tiles/Tiles.tsx
CHANGED
|
@@ -14,19 +14,19 @@ export const Tiles = ({ children, className, loading = false, ...rest }: Props)
|
|
|
14
14
|
<Tile
|
|
15
15
|
key="placeholder1"
|
|
16
16
|
title="placeholder"
|
|
17
|
-
imageProps={{ src: 'placeholder'
|
|
17
|
+
imageProps={{ src: 'placeholder' }}
|
|
18
18
|
loading={true}
|
|
19
19
|
/>,
|
|
20
20
|
<Tile
|
|
21
21
|
key="placeholder2"
|
|
22
22
|
title="placeholder"
|
|
23
|
-
imageProps={{ src: 'placeholder'
|
|
23
|
+
imageProps={{ src: 'placeholder' }}
|
|
24
24
|
loading={true}
|
|
25
25
|
/>,
|
|
26
26
|
<Tile
|
|
27
27
|
key="placeholder3"
|
|
28
28
|
title="placeholder"
|
|
29
|
-
imageProps={{ src: 'placeholder'
|
|
29
|
+
imageProps={{ src: 'placeholder' }}
|
|
30
30
|
loading={true}
|
|
31
31
|
/>,
|
|
32
32
|
];
|