@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
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { RefObject } from 'react';
|
|
1
|
+
import React, { Fragment, RefObject } from 'react';
|
|
2
2
|
import { BaseButton, Props as BaseButtonProps } from './BaseButton';
|
|
3
3
|
import classes from './IconButton.module.scss';
|
|
4
4
|
import readyclasses from '../readyclasses.module.scss';
|
|
@@ -7,22 +7,26 @@ export interface Props extends Omit<BaseButtonProps, 'ref'> {
|
|
|
7
7
|
children?: React.ReactNode;
|
|
8
8
|
iconSize?: 's' | 'm' | 'l';
|
|
9
9
|
className?: string;
|
|
10
|
-
title
|
|
10
|
+
title?: string;
|
|
11
11
|
ref?: RefObject<HTMLButtonElement>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const IconButton = React.forwardRef<HTMLButtonElement, Props>(
|
|
15
15
|
({ children, color = 'primary', iconSize = 'm', title, ...rest }, ref) => {
|
|
16
|
+
if (!title) {
|
|
17
|
+
console.error("Please make sure to specify a 'title' prop to your IconButton component! ");
|
|
18
|
+
}
|
|
19
|
+
|
|
16
20
|
return (
|
|
17
21
|
<BaseButton
|
|
18
22
|
{...rest}
|
|
19
23
|
ref={ref}
|
|
20
24
|
className={`${classes['icon-button']} ${classes[color]} ${classes['button-' + iconSize]}`}
|
|
21
25
|
>
|
|
22
|
-
|
|
26
|
+
<Fragment>
|
|
23
27
|
{children}
|
|
24
28
|
<span className={readyclasses['sr-only']}>{title}</span>
|
|
25
|
-
|
|
29
|
+
</Fragment>
|
|
26
30
|
</BaseButton>
|
|
27
31
|
);
|
|
28
32
|
}
|
|
@@ -77,16 +77,17 @@ export const Checkbox = ({
|
|
|
77
77
|
|
|
78
78
|
const renderNestedCheckboxes = () => (
|
|
79
79
|
<ul className={classes['checkbox-list']}>
|
|
80
|
-
{React.Children.map(children as
|
|
80
|
+
{React.Children.map(children as ReactNode[], (child) => {
|
|
81
81
|
return (
|
|
82
82
|
<li>
|
|
83
83
|
<Checkbox
|
|
84
|
-
{...child.props}
|
|
84
|
+
{...(child as ReactElement).props}
|
|
85
85
|
parentHelperId={parentHelperId}
|
|
86
86
|
parentErrorId={parentErrorId}
|
|
87
87
|
error={error}
|
|
88
|
+
disabled={disabled ? disabled : (child as CheckboxProps).disabled}
|
|
88
89
|
>
|
|
89
|
-
{child.props.children}
|
|
90
|
+
{(child as ReactElement).props.children}
|
|
90
91
|
</Checkbox>
|
|
91
92
|
</li>
|
|
92
93
|
);
|
|
@@ -103,6 +104,8 @@ export const Checkbox = ({
|
|
|
103
104
|
|
|
104
105
|
const renderToggle = () => React.Children.toArray(children).filter(isToggle);
|
|
105
106
|
|
|
107
|
+
const iconClasses = [classes['input'], disabled ? classes['disabled'] : ''];
|
|
108
|
+
|
|
106
109
|
/** Default return value is the default checkbox */
|
|
107
110
|
return (
|
|
108
111
|
<FormSelectorWrapper
|
|
@@ -136,9 +139,11 @@ export const Checkbox = ({
|
|
|
136
139
|
/>
|
|
137
140
|
{renderToggle()}
|
|
138
141
|
|
|
139
|
-
{indeterminate && <Icon className={
|
|
140
|
-
{checked && !indeterminate &&
|
|
141
|
-
|
|
142
|
+
{indeterminate && <Icon className={iconClasses.join(' ')} icon={Icons.MinusSquare} />}
|
|
143
|
+
{checked && !indeterminate && (
|
|
144
|
+
<Icon className={iconClasses.join(' ')} icon={Icons.CheckmarkSquare} />
|
|
145
|
+
)}
|
|
146
|
+
{!checked && !indeterminate && <Icon className={iconClasses.join(' ')} icon={Icons.Square} />}
|
|
142
147
|
<label htmlFor={`${identifier}-checkbox`}>{determineLabel()}</label>
|
|
143
148
|
</FormSelectorWrapper>
|
|
144
149
|
);
|
|
@@ -7,8 +7,8 @@ import { Select } from '../Select/Select';
|
|
|
7
7
|
import { Option } from '../Select/Option';
|
|
8
8
|
|
|
9
9
|
const defaultParams: Props = {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
legend: 'Example',
|
|
11
|
+
legendStyle: 'h2',
|
|
12
12
|
children: [
|
|
13
13
|
<FormControl data-testid="form-control">
|
|
14
14
|
<Input placeholder="This is a placeholder" name="example" type="text" />
|
|
@@ -6,24 +6,28 @@ import { Typography, Variant } from '../../Typography/Typography';
|
|
|
6
6
|
|
|
7
7
|
export interface Props extends HTMLProps<HTMLFieldSetElement> {
|
|
8
8
|
children?: ReactElement | ReactElement[];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
legend: string;
|
|
10
|
+
legendStyle?: Variant;
|
|
11
|
+
hideLegend?: boolean;
|
|
12
12
|
background?: string;
|
|
13
13
|
noPadding?: boolean;
|
|
14
14
|
noBackground?: boolean;
|
|
15
|
+
required?: boolean;
|
|
16
|
+
error?: boolean;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export const Fieldset = ({
|
|
18
20
|
children,
|
|
19
21
|
className,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
legend,
|
|
23
|
+
legendStyle = 'body',
|
|
24
|
+
hideLegend = false,
|
|
23
25
|
noBackground,
|
|
24
26
|
background = noBackground ? '' : '#FFF',
|
|
25
27
|
noPadding = false,
|
|
26
28
|
disabled = false,
|
|
29
|
+
required = false,
|
|
30
|
+
error = false,
|
|
27
31
|
...rest
|
|
28
32
|
}: Props) => {
|
|
29
33
|
const renderChildren = () => {
|
|
@@ -32,6 +36,7 @@ export const Fieldset = ({
|
|
|
32
36
|
return React.Children.map(children, (child: ReactElement) =>
|
|
33
37
|
React.cloneElement(child, {
|
|
34
38
|
disabled: child.props.disabled !== undefined ? child.props.disabled : disabled,
|
|
39
|
+
error: child.props.error !== undefined ? child.props.error : error,
|
|
35
40
|
})
|
|
36
41
|
);
|
|
37
42
|
};
|
|
@@ -43,10 +48,17 @@ export const Fieldset = ({
|
|
|
43
48
|
style={{ backgroundColor: background, ...rest.style }}
|
|
44
49
|
className={`${classes.fieldset} ${noPadding ? classes['no-padding'] : ''} ${className ?? ''}`}
|
|
45
50
|
>
|
|
46
|
-
{
|
|
47
|
-
{
|
|
48
|
-
<Typography
|
|
49
|
-
{
|
|
51
|
+
{legend && <legend className={readyclasses['sr-only']}>{legend}</legend>}
|
|
52
|
+
{legend && !hideLegend && (
|
|
53
|
+
<Typography
|
|
54
|
+
variant={legendStyle}
|
|
55
|
+
tag="span"
|
|
56
|
+
aria-hidden="true"
|
|
57
|
+
className={`${classes['legend']} ${required ? classes['required'] : ''} ${
|
|
58
|
+
error ? classes['error'] : ''
|
|
59
|
+
}`}
|
|
60
|
+
>
|
|
61
|
+
{legend}
|
|
50
62
|
</Typography>
|
|
51
63
|
)}
|
|
52
64
|
{renderChildren()}
|
|
@@ -6,11 +6,13 @@ export interface Props extends HTMLProps<HTMLDivElement> {
|
|
|
6
6
|
children: ReactElement | ReactElement[];
|
|
7
7
|
grid?: 1 | 2 | 3;
|
|
8
8
|
align?: 'top' | 'start' | 'middle' | 'center' | 'bottom' | 'end' | 'stretch';
|
|
9
|
+
error?: boolean;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export const FormControl = ({
|
|
12
13
|
children,
|
|
13
14
|
disabled,
|
|
15
|
+
error,
|
|
14
16
|
className,
|
|
15
17
|
grid,
|
|
16
18
|
align = 'center',
|
|
@@ -24,6 +26,7 @@ export const FormControl = ({
|
|
|
24
26
|
|
|
25
27
|
const childElement = React.cloneElement(child, {
|
|
26
28
|
disabled: child.props.disabled !== undefined ? child.props.disabled : disabled,
|
|
29
|
+
error: child.props.error !== undefined ? child.props.error : error,
|
|
27
30
|
});
|
|
28
31
|
|
|
29
32
|
if (grid && grid > 1) {
|
package/src/Form/Radio/Radio.tsx
CHANGED
|
@@ -87,8 +87,18 @@ export const Radio = ({
|
|
|
87
87
|
type="radio"
|
|
88
88
|
/>
|
|
89
89
|
|
|
90
|
-
{checked &&
|
|
91
|
-
|
|
90
|
+
{checked && (
|
|
91
|
+
<Icon
|
|
92
|
+
className={`${classes['input']} ${disabled ? classes['disabled'] : ''}`}
|
|
93
|
+
icon={Icons.Radio}
|
|
94
|
+
/>
|
|
95
|
+
)}
|
|
96
|
+
{!checked && (
|
|
97
|
+
<Icon
|
|
98
|
+
className={`${classes['input']} ${disabled ? classes['disabled'] : ''}`}
|
|
99
|
+
icon={Icons.Circle}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
92
102
|
|
|
93
103
|
<label onClick={onChangeHandler} htmlFor={`${identifier}-radio`}>
|
|
94
104
|
{children}
|
|
@@ -21,7 +21,7 @@ export const CheckboxWrapper = ({
|
|
|
21
21
|
const { errorId, helperId } = useWrapper();
|
|
22
22
|
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
if (fieldsetProps.
|
|
24
|
+
if (fieldsetProps.legend === undefined) {
|
|
25
25
|
console.error(
|
|
26
26
|
`You should give your Fieldset component a title prop so a legend element is rendered. This error was thrown in CheckboxWrapper. You can add this title prop through the fieldsetProps prop by passing an object (fieldsetProps={{ title: "title here" }})`
|
|
27
27
|
);
|
|
@@ -12,7 +12,7 @@ const defaultParams: Props = {
|
|
|
12
12
|
helperText: 'Helper text',
|
|
13
13
|
error: false,
|
|
14
14
|
onChange: onChangeHandler,
|
|
15
|
-
fieldsetProps: {
|
|
15
|
+
fieldsetProps: { legend: 'Example title' },
|
|
16
16
|
value: checkedOptionValue,
|
|
17
17
|
name: 'my-group',
|
|
18
18
|
children: [
|
|
@@ -27,7 +27,7 @@ export const RadioWrapper = ({
|
|
|
27
27
|
const { errorId, helperId } = useWrapper(value);
|
|
28
28
|
|
|
29
29
|
useEffect(() => {
|
|
30
|
-
if (fieldsetProps.
|
|
30
|
+
if (fieldsetProps.legend === undefined) {
|
|
31
31
|
console.error(
|
|
32
32
|
`You should give your Fieldset component a title prop so a legend element is rendered. This error was thrown in RadioWrapper. You can add this title prop through the fieldsetProps prop by passing an object (fieldsetProps={{ title: "title here" }})`
|
|
33
33
|
);
|
|
@@ -4,10 +4,11 @@ import { Wrapper, WrapperProps } from '../Wrapper/Wrapper';
|
|
|
4
4
|
import { Select, Props as SelectProps } from '../../Select/Select';
|
|
5
5
|
import { useWrapper } from '../../../hooks/useWrapper';
|
|
6
6
|
|
|
7
|
-
export interface Props extends Omit<WrapperProps, 'onChange'> {
|
|
7
|
+
export interface Props extends Omit<WrapperProps, 'onChange' | 'error'> {
|
|
8
8
|
children: ReactChild | ReactChild[];
|
|
9
9
|
placeholder?: string;
|
|
10
10
|
value: string;
|
|
11
|
+
error?: boolean;
|
|
11
12
|
selectProps?: SelectProps;
|
|
12
13
|
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
|
|
13
14
|
onClear?: () => void;
|
|
File without changes
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { BaseModal, Props } from './BaseModal';
|
|
3
|
-
import {
|
|
4
|
-
render,
|
|
5
|
-
getByRole,
|
|
6
|
-
getByText,
|
|
7
|
-
queryByText,
|
|
8
|
-
queryByRole,
|
|
9
|
-
fireEvent,
|
|
10
|
-
} from '@testing-library/react';
|
|
3
|
+
import { render, getByText, queryByText, fireEvent } from '@testing-library/react';
|
|
11
4
|
import userEvent from '@testing-library/user-event';
|
|
12
5
|
|
|
13
6
|
const classNames = ['class11', 'class12'];
|
|
@@ -24,8 +17,8 @@ const initParams: Props = {
|
|
|
24
17
|
|
|
25
18
|
describe('BaseModal', () => {
|
|
26
19
|
it('renders without crashing', () => {
|
|
27
|
-
const {
|
|
28
|
-
const dialog = getByRole(
|
|
20
|
+
const { getByRole } = render(<BaseModal {...initParams} />);
|
|
21
|
+
const dialog = getByRole('dialog');
|
|
29
22
|
expect(dialog).toHaveAttribute('aria-modal', 'true');
|
|
30
23
|
expect(dialog).toHaveAttribute('aria-labelledby', 'modal-label');
|
|
31
24
|
expect(dialog).toHaveAttribute('aria-describedby', 'modal-description');
|
|
@@ -36,17 +29,17 @@ describe('BaseModal', () => {
|
|
|
36
29
|
});
|
|
37
30
|
|
|
38
31
|
it('should render close modal without content', () => {
|
|
39
|
-
const {
|
|
40
|
-
const dialogByRole = queryByRole(
|
|
41
|
-
const dialog =
|
|
32
|
+
const { queryByRole } = render(<BaseModal {...initParams} open={false} />);
|
|
33
|
+
const dialogByRole = queryByRole('dialog');
|
|
34
|
+
const dialog = document.body.children[1] as HTMLElement;
|
|
42
35
|
expect(dialogByRole).toBeNull();
|
|
43
36
|
expect(dialog).toHaveAttribute('aria-hidden', 'true');
|
|
44
37
|
expect(queryByText(dialog, initParams.children as string)).toBeNull();
|
|
45
38
|
});
|
|
46
39
|
|
|
47
40
|
it('should handle clicking on backdrop & ESC key', () => {
|
|
48
|
-
const {
|
|
49
|
-
const modal = getByRole(
|
|
41
|
+
const { getByRole } = render(<BaseModal {...initParams} />);
|
|
42
|
+
const modal = getByRole('dialog');
|
|
50
43
|
const backdrop = modal.querySelector('.backdrop') as HTMLElement;
|
|
51
44
|
expect(initParams.onClose).toHaveBeenCalledTimes(0);
|
|
52
45
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { HTMLAttributes } from '../../interfaces';
|
|
2
4
|
import classes from './BaseModal.module.scss';
|
|
3
5
|
import { labelId, descriptionId } from './BaseModalContext';
|
|
4
6
|
|
|
@@ -17,27 +19,9 @@ export interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
|
17
19
|
disableEscapeKeyDown?: boolean;
|
|
18
20
|
disableBackdrop?: boolean;
|
|
19
21
|
zIndex?: number;
|
|
22
|
+
domRoot?: HTMLElement;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
const useBackdropOnCloseClick = (
|
|
23
|
-
disableBackdrop: boolean,
|
|
24
|
-
onClose?: (event?: React.MouseEvent<HTMLElement>) => unknown
|
|
25
|
-
) => {
|
|
26
|
-
const backdropRef = useRef<HTMLDivElement>(null);
|
|
27
|
-
const onBackdropClick = () => onClose && onClose();
|
|
28
|
-
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
!disableBackdrop && backdropRef.current?.addEventListener('click', onBackdropClick);
|
|
31
|
-
return () => {
|
|
32
|
-
!disableBackdrop && backdropRef.current?.removeEventListener('click', onBackdropClick);
|
|
33
|
-
};
|
|
34
|
-
}, []);
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
backdropRef,
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
|
|
41
25
|
export const useSetBodyScroll = (open: boolean) => {
|
|
42
26
|
const hideBodyScroll = () => {
|
|
43
27
|
document.body.style[SCROLL_PROPERTY_NAME] = SCROLL_PROPERTY_VALUE;
|
|
@@ -72,9 +56,9 @@ export const BaseModal = ({
|
|
|
72
56
|
disableEscapeKeyDown = false,
|
|
73
57
|
disableBackdrop = false,
|
|
74
58
|
zIndex,
|
|
59
|
+
domRoot = document.body,
|
|
75
60
|
...restProps
|
|
76
61
|
}: Props) => {
|
|
77
|
-
const { backdropRef } = useBackdropOnCloseClick(disableBackdrop, onClose);
|
|
78
62
|
useSetBodyScroll(open);
|
|
79
63
|
|
|
80
64
|
const handleEscKeyPress = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
@@ -84,7 +68,9 @@ export const BaseModal = ({
|
|
|
84
68
|
}
|
|
85
69
|
};
|
|
86
70
|
|
|
87
|
-
|
|
71
|
+
const handleBackdropClick = () => !disableBackdrop && onClose && onClose();
|
|
72
|
+
|
|
73
|
+
return createPortal(
|
|
88
74
|
<div
|
|
89
75
|
{...restProps}
|
|
90
76
|
id={id}
|
|
@@ -99,7 +85,7 @@ export const BaseModal = ({
|
|
|
99
85
|
onKeyDown={handleEscKeyPress}
|
|
100
86
|
style={{ zIndex }}
|
|
101
87
|
>
|
|
102
|
-
<div
|
|
88
|
+
<div className={classes['backdrop']} onClick={handleBackdropClick}></div>
|
|
103
89
|
{open && (
|
|
104
90
|
<div
|
|
105
91
|
style={{ zIndex: zIndex && zIndex + 1 }}
|
|
@@ -108,6 +94,7 @@ export const BaseModal = ({
|
|
|
108
94
|
{children}
|
|
109
95
|
</div>
|
|
110
96
|
)}
|
|
111
|
-
</div
|
|
97
|
+
</div>,
|
|
98
|
+
domRoot
|
|
112
99
|
);
|
|
113
100
|
};
|
package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.module.scss
RENAMED
|
File without changes
|
package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.test.tsx
RENAMED
|
File without changes
|
|
File without changes
|
package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.module.scss
RENAMED
|
File without changes
|
package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.test.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.module.scss
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { HTMLAttributes } from 'react';
|
|
2
2
|
import classes from './BaseModalHeader.module.scss';
|
|
3
|
-
import { IconButton } from '
|
|
4
|
-
import { Icon, Icons } from '
|
|
5
|
-
import { Typography } from '
|
|
3
|
+
import { IconButton } from '../../../Button/IconButton';
|
|
4
|
+
import { Icon, Icons } from '../../../Icon/Icon';
|
|
5
|
+
import { Typography } from '../../../Typography/Typography';
|
|
6
6
|
|
|
7
|
-
export interface Props extends HTMLAttributes<
|
|
7
|
+
export interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
8
8
|
id: string;
|
|
9
9
|
title: string;
|
|
10
10
|
children?: React.ReactNode;
|
|
@@ -13,7 +13,7 @@ export interface Props extends HTMLAttributes<HTMLElement> {
|
|
|
13
13
|
|
|
14
14
|
export const BaseModalHeader = ({ id, title, children, onClose, ...restProps }: Props) => {
|
|
15
15
|
return (
|
|
16
|
-
<
|
|
16
|
+
<div {...restProps} className={classes['header']}>
|
|
17
17
|
<div className={classes['headline']}>
|
|
18
18
|
<Typography id={id} className={classes['title']} tag="h1" variant="h4">
|
|
19
19
|
{title}
|
|
@@ -23,6 +23,6 @@ export const BaseModalHeader = ({ id, title, children, onClose, ...restProps }:
|
|
|
23
23
|
</IconButton>
|
|
24
24
|
</div>
|
|
25
25
|
{children}
|
|
26
|
-
</
|
|
26
|
+
</div>
|
|
27
27
|
);
|
|
28
28
|
};
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Dialog, Props } from './Dialog';
|
|
3
|
-
import { render, getAllByRole
|
|
3
|
+
import { render, getAllByRole } from '@testing-library/react';
|
|
4
4
|
import userEvent from '@testing-library/user-event';
|
|
5
5
|
|
|
6
6
|
const initParams: Props = {
|
|
@@ -24,11 +24,11 @@ const getButtons = (container: HTMLElement) => getAllByRole(container, 'button')
|
|
|
24
24
|
|
|
25
25
|
describe('Dialog', () => {
|
|
26
26
|
it('renders without crashing', () => {
|
|
27
|
-
const {
|
|
28
|
-
const [primaryButton, secondaryButton] = getButtons(
|
|
27
|
+
const { getByText } = render(<Dialog {...initParams} />);
|
|
28
|
+
const [primaryButton, secondaryButton] = getButtons(document.body);
|
|
29
29
|
|
|
30
|
-
expect(getByText(
|
|
31
|
-
expect(getByText(
|
|
30
|
+
expect(getByText(initParams.title)).toBeDefined();
|
|
31
|
+
expect(getByText(initParams.children as string)).toBeDefined();
|
|
32
32
|
const actionsDiv = primaryButton.closest('footer');
|
|
33
33
|
expect(actionsDiv).toHaveClass('left');
|
|
34
34
|
expect(actionsDiv?.children[0]).toEqual(primaryButton);
|
|
@@ -38,8 +38,8 @@ describe('Dialog', () => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('renders action aligned to right', () => {
|
|
41
|
-
|
|
42
|
-
const [secondaryButton, primaryButton] = getButtons(
|
|
41
|
+
render(<Dialog {...initParams} alignActions="right" />);
|
|
42
|
+
const [secondaryButton, primaryButton] = getButtons(document.body);
|
|
43
43
|
|
|
44
44
|
const actionsDiv = primaryButton.closest('footer');
|
|
45
45
|
expect(actionsDiv).not.toHaveClass('left');
|
|
@@ -50,27 +50,24 @@ describe('Dialog', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('renders only one button', () => {
|
|
53
|
-
|
|
54
|
-
const buttons = getButtons(
|
|
53
|
+
render(<Dialog {...initParams} secondaryAction={undefined} />);
|
|
54
|
+
const buttons = getButtons(document.body);
|
|
55
55
|
|
|
56
56
|
expect(buttons).toHaveLength(1);
|
|
57
57
|
expect(buttons[0]).toHaveClass('fill');
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
it('should handle clicking on buttons
|
|
61
|
-
|
|
62
|
-
const [primaryButton, secondaryButton] = getButtons(
|
|
60
|
+
it('should handle clicking on buttons and ENTER press', () => {
|
|
61
|
+
render(<Dialog {...initParams} />);
|
|
62
|
+
const [primaryButton, secondaryButton] = getButtons(document.body);
|
|
63
63
|
expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(0);
|
|
64
64
|
expect(initParams.secondaryAction?.onClick).toHaveBeenCalledTimes(0);
|
|
65
65
|
expect(initParams.onClose).toHaveBeenCalledTimes(0);
|
|
66
66
|
|
|
67
|
-
const autoSummissionInput =
|
|
67
|
+
const autoSummissionInput = document.body.querySelector('input') as HTMLElement;
|
|
68
68
|
userEvent.type(autoSummissionInput, '{enter}');
|
|
69
69
|
expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(1);
|
|
70
70
|
|
|
71
|
-
fireEvent.keyDown(getByRole(container, 'dialog'), { key: 'Escape' });
|
|
72
|
-
expect(initParams.onClose).toHaveBeenCalledTimes(1);
|
|
73
|
-
|
|
74
71
|
userEvent.click(primaryButton);
|
|
75
72
|
expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(2);
|
|
76
73
|
userEvent.click(secondaryButton);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import React, { HTMLAttributes } from 'react';
|
|
1
|
+
import React, { HTMLAttributes, useState } from 'react';
|
|
2
2
|
import { BaseModal } from '../BaseModal/BaseModal';
|
|
3
3
|
import { BaseModalContent } from '../BaseModal/BaseModalContent/BaseModalContent';
|
|
4
4
|
import { DialogActions } from './DialogActions/DialogActions';
|
|
5
5
|
import classes from './Dialog.module.scss';
|
|
6
6
|
import { DialogTitle } from './DialogTitle/DialogTitle';
|
|
7
|
-
import { Button, Props as ButtonProps } from '
|
|
7
|
+
import { Button, Props as ButtonProps } from '../../Button/Button';
|
|
8
8
|
import { labelId, descriptionId } from '../BaseModal/BaseModalContext';
|
|
9
|
+
import { generateID } from '../../util/helper';
|
|
9
10
|
|
|
10
11
|
export interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
11
|
-
id
|
|
12
|
+
id?: string;
|
|
12
13
|
open: boolean;
|
|
13
14
|
children: React.ReactNode;
|
|
14
15
|
alignActions: 'left' | 'right';
|
|
@@ -17,6 +18,7 @@ export interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
|
17
18
|
primaryAction: Action;
|
|
18
19
|
secondaryAction?: Action;
|
|
19
20
|
zIndex?: number;
|
|
21
|
+
disableEscapeKeyDown?: boolean;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface Action extends Omit<ButtonProps, 'variant' | 'ref'> {
|
|
@@ -34,8 +36,10 @@ export const Dialog = ({
|
|
|
34
36
|
primaryAction,
|
|
35
37
|
secondaryAction,
|
|
36
38
|
zIndex,
|
|
39
|
+
disableEscapeKeyDown = true,
|
|
37
40
|
...restProps
|
|
38
41
|
}: Props) => {
|
|
42
|
+
const [dialogId] = useState(id ?? generateID(20));
|
|
39
43
|
const { label: primaryLabel, ...restOfPrimaryAction } = primaryAction;
|
|
40
44
|
const PrimaryButton = (
|
|
41
45
|
<Button key="primary" {...restOfPrimaryAction}>
|
|
@@ -63,16 +67,21 @@ export const Dialog = ({
|
|
|
63
67
|
return (
|
|
64
68
|
<BaseModal
|
|
65
69
|
{...restProps}
|
|
66
|
-
id={
|
|
70
|
+
id={dialogId}
|
|
67
71
|
className={classes['dialog']}
|
|
68
72
|
containerClassName={classes['container']}
|
|
69
73
|
open={open}
|
|
70
74
|
disableBackdrop
|
|
71
75
|
onClose={onClose}
|
|
72
76
|
zIndex={zIndex}
|
|
77
|
+
disableEscapeKeyDown={disableEscapeKeyDown}
|
|
73
78
|
>
|
|
74
|
-
<DialogTitle id={labelId(
|
|
75
|
-
<BaseModalContent
|
|
79
|
+
<DialogTitle id={labelId(dialogId)} title={title} />
|
|
80
|
+
<BaseModalContent
|
|
81
|
+
id={descriptionId(dialogId)}
|
|
82
|
+
className={classes['content']}
|
|
83
|
+
disableAutoFocus
|
|
84
|
+
>
|
|
76
85
|
{children}
|
|
77
86
|
</BaseModalContent>
|
|
78
87
|
<DialogActions align={alignActions}>
|
|
@@ -82,12 +91,14 @@ export const Dialog = ({
|
|
|
82
91
|
</DialogActions>
|
|
83
92
|
<input
|
|
84
93
|
autoFocus
|
|
94
|
+
aria-hidden={true}
|
|
85
95
|
style={{
|
|
86
96
|
position: 'absolute',
|
|
87
97
|
width: 0,
|
|
88
98
|
height: 0,
|
|
89
99
|
opacity: 0,
|
|
90
100
|
}}
|
|
101
|
+
maxLength={0}
|
|
91
102
|
tabIndex={-1}
|
|
92
103
|
onKeyPress={onHiddenInputKeyPress}
|
|
93
104
|
/>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|