@react-ui-org/react-ui 0.51.0 → 0.52.1
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/lib.development.js +141 -33
- package/dist/lib.js +1 -1
- package/dist/react-ui.css +40 -0
- package/dist/react-ui.js +1 -0
- package/package.json +1 -1
- package/src/lib/components/Button/Button.jsx +17 -9
- package/src/lib/components/Button/_base.scss +21 -12
- package/src/lib/components/Button/_priorities.scss +1 -18
- package/src/lib/components/Button/_theme.scss +0 -10
- package/src/lib/components/ButtonGroup/ButtonGroup.jsx +5 -3
- package/src/lib/components/ButtonGroup/ButtonGroup.scss +26 -1
- package/src/lib/components/ButtonGroup/README.mdx +11 -1
- package/src/lib/components/ButtonGroup/_theme.scss +13 -0
- package/src/lib/components/FormLayout/README.mdx +5 -0
- package/src/lib/components/InputGroup/InputGroup.jsx +170 -0
- package/src/lib/components/InputGroup/InputGroup.scss +92 -0
- package/src/lib/components/InputGroup/InputGroupContext.js +3 -0
- package/src/lib/components/InputGroup/README.mdx +278 -0
- package/src/lib/components/InputGroup/_theme.scss +2 -0
- package/src/lib/components/InputGroup/index.js +2 -0
- package/src/lib/components/Modal/Modal.jsx +58 -97
- package/src/lib/components/Modal/README.mdx +288 -15
- package/src/lib/components/Modal/_helpers/getPositionClassName.js +7 -0
- package/src/lib/components/Modal/_helpers/getSizeClassName.js +19 -0
- package/src/lib/components/Modal/_hooks/useModalFocus.js +126 -0
- package/src/lib/components/Modal/_hooks/useModalScrollPrevention.js +35 -0
- package/src/lib/components/Modal/_settings.scss +1 -1
- package/src/lib/components/Radio/README.mdx +9 -1
- package/src/lib/components/Radio/Radio.jsx +39 -31
- package/src/lib/components/Radio/Radio.scss +12 -2
- package/src/lib/components/SelectField/SelectField.jsx +21 -8
- package/src/lib/components/SelectField/SelectField.scss +5 -0
- package/src/lib/components/TextField/TextField.jsx +21 -8
- package/src/lib/components/TextField/TextField.scss +5 -0
- package/src/lib/index.js +1 -0
- package/src/lib/styles/theme/_borders.scss +2 -1
- package/src/lib/styles/tools/form-fields/_box-field-elements.scss +19 -2
- package/src/lib/styles/tools/form-fields/_box-field-layout.scss +26 -14
- package/src/lib/styles/tools/form-fields/_box-field-sizes.scss +11 -8
- package/src/lib/styles/tools/form-fields/_foundation.scss +7 -0
- package/src/lib/theme.scss +23 -11
- /package/src/lib/components/{Button/helpers → _helpers}/getRootPriorityClassName.js +0 -0
@@ -1,12 +1,13 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
|
-
import React, {
|
3
|
-
useEffect,
|
4
|
-
useRef,
|
5
|
-
} from 'react';
|
2
|
+
import React, { useRef } from 'react';
|
6
3
|
import { createPortal } from 'react-dom';
|
7
4
|
import { withGlobalProps } from '../../provider';
|
8
5
|
import { transferProps } from '../_helpers/transferProps';
|
9
6
|
import { classNames } from '../../utils/classNames';
|
7
|
+
import { getPositionClassName } from './_helpers/getPositionClassName';
|
8
|
+
import { getSizeClassName } from './_helpers/getSizeClassName';
|
9
|
+
import { useModalFocus } from './_hooks/useModalFocus';
|
10
|
+
import { useModalScrollPrevention } from './_hooks/useModalScrollPrevention';
|
10
11
|
import styles from './Modal.scss';
|
11
12
|
|
12
13
|
const preRender = (
|
@@ -16,63 +17,34 @@ const preRender = (
|
|
16
17
|
position,
|
17
18
|
restProps,
|
18
19
|
size,
|
19
|
-
) =>
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
|
30
|
-
return styles.isRootSizeLarge;
|
31
|
-
}
|
32
|
-
|
33
|
-
if (modalSize === 'fullscreen') {
|
34
|
-
return styles.isRootSizeFullscreen;
|
35
|
-
}
|
36
|
-
|
37
|
-
return styles.isRootSizeAuto;
|
38
|
-
};
|
39
|
-
|
40
|
-
const positionClass = (modalPosition) => {
|
41
|
-
if (modalPosition === 'top') {
|
42
|
-
return styles.isRootPositionTop;
|
43
|
-
}
|
44
|
-
|
45
|
-
return styles.isRootPositionCenter;
|
46
|
-
};
|
47
|
-
|
48
|
-
return (
|
20
|
+
) => (
|
21
|
+
<div
|
22
|
+
className={styles.backdrop}
|
23
|
+
onClick={(e) => {
|
24
|
+
e.preventDefault();
|
25
|
+
if (closeButtonRef?.current != null) {
|
26
|
+
closeButtonRef.current.click();
|
27
|
+
}
|
28
|
+
}}
|
29
|
+
role="presentation"
|
30
|
+
>
|
49
31
|
<div
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
32
|
+
{...transferProps(restProps)}
|
33
|
+
className={classNames(
|
34
|
+
styles.root,
|
35
|
+
getSizeClassName(size, styles),
|
36
|
+
getPositionClassName(position, styles),
|
37
|
+
)}
|
38
|
+
onClick={(e) => {
|
39
|
+
e.stopPropagation();
|
55
40
|
}}
|
56
41
|
role="presentation"
|
42
|
+
ref={childrenWrapperRef}
|
57
43
|
>
|
58
|
-
|
59
|
-
{...transferProps(restProps)}
|
60
|
-
className={classNames(
|
61
|
-
styles.root,
|
62
|
-
sizeClass(size),
|
63
|
-
positionClass(position),
|
64
|
-
)}
|
65
|
-
onClick={(e) => {
|
66
|
-
e.stopPropagation();
|
67
|
-
}}
|
68
|
-
role="presentation"
|
69
|
-
ref={childrenWrapperRef}
|
70
|
-
>
|
71
|
-
{children}
|
72
|
-
</div>
|
44
|
+
{children}
|
73
45
|
</div>
|
74
|
-
|
75
|
-
|
46
|
+
</div>
|
47
|
+
);
|
76
48
|
|
77
49
|
export const Modal = ({
|
78
50
|
autoFocus,
|
@@ -80,52 +52,21 @@ export const Modal = ({
|
|
80
52
|
closeButtonRef,
|
81
53
|
portalId,
|
82
54
|
position,
|
55
|
+
preventScrollUnderneath,
|
83
56
|
primaryButtonRef,
|
84
57
|
size,
|
85
58
|
...restProps
|
86
59
|
}) => {
|
87
60
|
const childrenWrapperRef = useRef();
|
88
61
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
primaryButtonRef.current.click();
|
96
|
-
}
|
97
|
-
};
|
98
|
-
|
99
|
-
useEffect(() => {
|
100
|
-
window.document.addEventListener('keydown', keyPressHandler, false);
|
101
|
-
const removeKeyPressHandler = () => {
|
102
|
-
window.document.removeEventListener('keydown', keyPressHandler, false);
|
103
|
-
};
|
104
|
-
|
105
|
-
// If `autoFocus` is set to `true`, following code finds first form field element
|
106
|
-
// (input, textarea or select) or primary button and auto focuses it. This is necessary
|
107
|
-
// to have focus on one of those elements to be able to submit form by pressing Enter key.
|
108
|
-
if (autoFocus) {
|
109
|
-
if (childrenWrapperRef?.current != null) {
|
110
|
-
const childrenWrapperElement = childrenWrapperRef.current;
|
111
|
-
const childrenElements = childrenWrapperElement.querySelectorAll('*');
|
112
|
-
const formFieldEl = Array.from(childrenElements).find(
|
113
|
-
(element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName) && !element.disabled,
|
114
|
-
);
|
115
|
-
|
116
|
-
if (formFieldEl) {
|
117
|
-
formFieldEl.focus();
|
118
|
-
return removeKeyPressHandler;
|
119
|
-
}
|
120
|
-
}
|
121
|
-
|
122
|
-
if (primaryButtonRef?.current != null) {
|
123
|
-
primaryButtonRef.current.focus();
|
124
|
-
}
|
125
|
-
}
|
62
|
+
useModalFocus(
|
63
|
+
autoFocus,
|
64
|
+
childrenWrapperRef,
|
65
|
+
primaryButtonRef,
|
66
|
+
closeButtonRef,
|
67
|
+
);
|
126
68
|
|
127
|
-
|
128
|
-
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
69
|
+
useModalScrollPrevention(preventScrollUnderneath);
|
129
70
|
|
130
71
|
if (portalId === null) {
|
131
72
|
return preRender(
|
@@ -157,14 +98,16 @@ Modal.defaultProps = {
|
|
157
98
|
closeButtonRef: null,
|
158
99
|
portalId: null,
|
159
100
|
position: 'center',
|
101
|
+
preventScrollUnderneath: 'default',
|
160
102
|
primaryButtonRef: null,
|
161
103
|
size: 'medium',
|
162
104
|
};
|
163
105
|
|
164
106
|
Modal.propTypes = {
|
165
107
|
/**
|
166
|
-
* If `true`, focus the first input element in the
|
167
|
-
* when the
|
108
|
+
* If `true`, focus the first input element in the `Modal`, or primary button (referenced by the `primaryButtonRef`
|
109
|
+
* prop), or other focusable element when the `Modal` is opened. If there are none or `autoFocus` is set to `false`,
|
110
|
+
* focus the Modal itself.
|
168
111
|
*/
|
169
112
|
autoFocus: PropTypes.bool,
|
170
113
|
/**
|
@@ -192,6 +135,24 @@ Modal.propTypes = {
|
|
192
135
|
* Vertical position of the modal inside browser window.
|
193
136
|
*/
|
194
137
|
position: PropTypes.oneOf(['top', 'center']),
|
138
|
+
/**
|
139
|
+
* Mode in which Modal prevents scroll of elements bellow:
|
140
|
+
* * `default` - Modal prevents scroll on the `body` element
|
141
|
+
* * `off` - Modal does not prevent any scroll
|
142
|
+
* * object
|
143
|
+
* * * `reset` - method called on Modal's unmount to reset scroll prevention
|
144
|
+
* * * `start` - method called on Modal's mount to custom scroll prevention
|
145
|
+
*/
|
146
|
+
preventScrollUnderneath: PropTypes.oneOfType([
|
147
|
+
PropTypes.oneOf([
|
148
|
+
'default',
|
149
|
+
'off',
|
150
|
+
]),
|
151
|
+
PropTypes.shape({
|
152
|
+
reset: PropTypes.func,
|
153
|
+
start: PropTypes.func,
|
154
|
+
}),
|
155
|
+
]),
|
195
156
|
/**
|
196
157
|
* Reference to primary button element. It is used to submit modal when Enter key is pressed and as fallback
|
197
158
|
* when `autoFocus` functionality does not find any input element to be focused.
|
@@ -25,6 +25,7 @@ import {
|
|
25
25
|
ModalTitle,
|
26
26
|
Radio,
|
27
27
|
ScrollView,
|
28
|
+
TextArea,
|
28
29
|
TextField,
|
29
30
|
Toolbar,
|
30
31
|
ToolbarGroup,
|
@@ -116,12 +117,15 @@ See [API](#api) for all available options.
|
|
116
117
|
|
117
118
|
- Modal **automatically focuses the first non-disabled form field** by default
|
118
119
|
which allows users to confirm the modal by hitting the enter key. When no
|
119
|
-
field is found then the primary button (in the footer) is focused.
|
120
|
-
|
120
|
+
field is found then the primary button (in the footer) is focused. If there
|
121
|
+
are neither, it tries to focus any other focusable elements. In case there
|
122
|
+
are none, or [autoFocus](#autoFocus) is disabled, Modal itself is focused.
|
121
123
|
|
122
124
|
- **Avoid stacking** of modals. While it may technically work, the modal is just
|
123
125
|
not designed for that.
|
124
126
|
|
127
|
+
📖 [Read more about modals at Nielsen Norman Group.][nng-modal]
|
128
|
+
|
125
129
|
## Composition
|
126
130
|
|
127
131
|
Modal is decomposed into the following components:
|
@@ -822,24 +826,147 @@ can be closed by pressing the `Escape` key.
|
|
822
826
|
|
823
827
|
To enable it, you just need to pass a reference to the buttons using
|
824
828
|
`primaryButtonRef` and `closeButtonRef` props on Modal. The advantage of passing
|
825
|
-
|
826
|
-
not fire the event.
|
827
|
-
|
828
|
-
👉 We strongly recommend using this feature together with
|
829
|
-
[Autofocus](#autofocus) for a better user experience.
|
829
|
+
the reference to the button is that if the button is disabled, the key press
|
830
|
+
will not fire the event.
|
830
831
|
|
831
832
|
## Autofocus
|
832
833
|
|
833
834
|
Autofocus is implemented to enhance the user experience by automatically
|
834
|
-
|
835
|
+
focusing an element within the Modal.
|
835
836
|
|
836
837
|
How does it work? It tries to find `input`, `textarea`, and `select` elements
|
837
838
|
inside of Modal and moves focus onto the first non-disabled one. If none is
|
838
839
|
found and the `primaryButtonRef` prop on Modal is set, then the primary button
|
839
|
-
is focused.
|
840
|
+
is focused. If there are neither, it tries to focus any other focusable elements.
|
841
|
+
In case there are none or `autoFocus` is disabled, Modal itself is focused.
|
840
842
|
|
841
|
-
|
842
|
-
|
843
|
+
<Playground>
|
844
|
+
{() => {
|
845
|
+
const [modalOpen, setModalOpen] = React.useState(null);
|
846
|
+
const modalPrimaryButtonRef = React.useRef();
|
847
|
+
const modalCloseButtonRef = React.useRef();
|
848
|
+
return (
|
849
|
+
<>
|
850
|
+
<Button
|
851
|
+
label="Launch modal with autofocus and form"
|
852
|
+
onClick={() => setModalOpen(1)}
|
853
|
+
/>
|
854
|
+
<Button
|
855
|
+
label="Launch modal with autofocus"
|
856
|
+
onClick={() => setModalOpen(2)}
|
857
|
+
/>
|
858
|
+
<Button
|
859
|
+
label="Launch modal with autofocus disabled"
|
860
|
+
onClick={() => setModalOpen(3)}
|
861
|
+
/>
|
862
|
+
<div>
|
863
|
+
{modalOpen === 1 && (
|
864
|
+
<Modal
|
865
|
+
closeButtonRef={modalCloseButtonRef}
|
866
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
867
|
+
>
|
868
|
+
<ModalHeader>
|
869
|
+
<ModalTitle>Modal with autoFocus and form</ModalTitle>
|
870
|
+
<ModalCloseButton onClick={() => setModalOpen(null)} />
|
871
|
+
</ModalHeader>
|
872
|
+
<ModalBody>
|
873
|
+
<ModalContent>
|
874
|
+
<FormLayout autoWidth fieldLayout="horizontal">
|
875
|
+
<TextField
|
876
|
+
disabled
|
877
|
+
label="A form element"
|
878
|
+
/>
|
879
|
+
<TextField label="Another form element" />
|
880
|
+
<TextArea label="Yet another one" />
|
881
|
+
</FormLayout>
|
882
|
+
</ModalContent>
|
883
|
+
</ModalBody>
|
884
|
+
<ModalFooter>
|
885
|
+
<Button
|
886
|
+
label="Submit"
|
887
|
+
onClick={() => setModalOpen(null)}
|
888
|
+
ref={modalPrimaryButtonRef}
|
889
|
+
/>
|
890
|
+
<Button
|
891
|
+
color="secondary"
|
892
|
+
label="Close"
|
893
|
+
onClick={() => setModalOpen(null)}
|
894
|
+
priority="outline"
|
895
|
+
ref={modalCloseButtonRef}
|
896
|
+
/>
|
897
|
+
</ModalFooter>
|
898
|
+
</Modal>
|
899
|
+
)}
|
900
|
+
{modalOpen === 2 && (
|
901
|
+
<Modal
|
902
|
+
closeButtonRef={modalCloseButtonRef}
|
903
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
904
|
+
>
|
905
|
+
<ModalHeader>
|
906
|
+
<ModalTitle>Modal with autoFocus enabled with no form</ModalTitle>
|
907
|
+
<ModalCloseButton onClick={() => setModalOpen(null)} />
|
908
|
+
</ModalHeader>
|
909
|
+
<ModalBody>
|
910
|
+
<ModalContent>
|
911
|
+
<p>
|
912
|
+
This Modal autofocuses the primary button or any other
|
913
|
+
focusable element.
|
914
|
+
</p>
|
915
|
+
</ModalContent>
|
916
|
+
</ModalBody>
|
917
|
+
<ModalFooter>
|
918
|
+
<Button
|
919
|
+
label="Acknowledge"
|
920
|
+
onClick={() => setModalOpen(null)}
|
921
|
+
ref={modalPrimaryButtonRef}
|
922
|
+
/>
|
923
|
+
<Button
|
924
|
+
color="secondary"
|
925
|
+
label="Close"
|
926
|
+
onClick={() => setModalOpen(null)}
|
927
|
+
priority="outline"
|
928
|
+
ref={modalCloseButtonRef}
|
929
|
+
/>
|
930
|
+
</ModalFooter>
|
931
|
+
</Modal>
|
932
|
+
)}
|
933
|
+
{modalOpen === 3 && (
|
934
|
+
<Modal
|
935
|
+
autoFocus={false}
|
936
|
+
closeButtonRef={modalCloseButtonRef}
|
937
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
938
|
+
>
|
939
|
+
<ModalHeader>
|
940
|
+
<ModalTitle>Modal with autoFocus disabled</ModalTitle>
|
941
|
+
</ModalHeader>
|
942
|
+
<ModalBody>
|
943
|
+
<ModalContent>
|
944
|
+
<p>
|
945
|
+
This Modal focuses the Modal element itself.
|
946
|
+
</p>
|
947
|
+
</ModalContent>
|
948
|
+
</ModalBody>
|
949
|
+
<ModalFooter>
|
950
|
+
<Button
|
951
|
+
label="Acknowledge"
|
952
|
+
onClick={() => setModalOpen(null)}
|
953
|
+
ref={modalPrimaryButtonRef}
|
954
|
+
/>
|
955
|
+
<Button
|
956
|
+
color="secondary"
|
957
|
+
label="Close"
|
958
|
+
onClick={() => setModalOpen(null)}
|
959
|
+
priority="outline"
|
960
|
+
ref={modalCloseButtonRef}
|
961
|
+
/>
|
962
|
+
</ModalFooter>
|
963
|
+
</Modal>
|
964
|
+
)}
|
965
|
+
</div>
|
966
|
+
</>
|
967
|
+
);
|
968
|
+
}}
|
969
|
+
</Playground>
|
843
970
|
|
844
971
|
## Scrolling Long Content
|
845
972
|
|
@@ -959,7 +1086,7 @@ independent of the page itself. This can be done in three ways using the
|
|
959
1086
|
<div>
|
960
1087
|
{modalOpen && (
|
961
1088
|
<Modal
|
962
|
-
autoFocus={
|
1089
|
+
autoFocus={modalScrolling !== 'none'}
|
963
1090
|
closeButtonRef={modalCloseButtonRef}
|
964
1091
|
primaryButtonRef={modalPrimaryButtonRef}
|
965
1092
|
size="small"
|
@@ -1003,9 +1130,154 @@ independent of the page itself. This can be done in three ways using the
|
|
1003
1130
|
|
1004
1131
|
### Long Content and Autofocus
|
1005
1132
|
|
1006
|
-
👉 If you
|
1007
|
-
|
1008
|
-
opened.
|
1133
|
+
👉 If you have a Modal with `scrolling` set to `none`, you may want to disable
|
1134
|
+
`autoFocus` to prevent the modal from scrolling to the end immediately after
|
1135
|
+
being opened.
|
1136
|
+
|
1137
|
+
## Prevent Scrolling Underneath the Modal
|
1138
|
+
|
1139
|
+
You can choose the mode in which Modal prevents the scroll of the page underneath.
|
1140
|
+
Default mode prevents scrolling on `<body>` element and accounts for the scrollbar
|
1141
|
+
width. If you choose `off`, there will be no scroll prevention. If you need more
|
1142
|
+
flexibility, define your methods `start` (called on Modal's mount) and `reset`
|
1143
|
+
(called on Modal unmount) wrapped by an object and handle scroll prevention
|
1144
|
+
yourself.
|
1145
|
+
|
1146
|
+
<Playground>
|
1147
|
+
{() => {
|
1148
|
+
const [modalOpen, setModalOpen] = React.useState(null);
|
1149
|
+
const modalPrimaryButtonRef = React.useRef();
|
1150
|
+
const modalCloseButtonRef = React.useRef();
|
1151
|
+
const customScrollPreventionObject = {
|
1152
|
+
start: () => {
|
1153
|
+
// YOUR CUSTOM SCROLL PREVENTING LOGIC GOES HERE
|
1154
|
+
window.document.body.style.overflowY = 'hidden'
|
1155
|
+
},
|
1156
|
+
reset: () => {
|
1157
|
+
// YOUR CUSTOM SCROLL RE-ENABLING LOGIC GOES HERE
|
1158
|
+
window.document.body.style.overflowY = 'auto'
|
1159
|
+
},
|
1160
|
+
};
|
1161
|
+
return (
|
1162
|
+
<>
|
1163
|
+
<Button
|
1164
|
+
label="Launch modal with default scroll prevention"
|
1165
|
+
onClick={() => setModalOpen(1)}
|
1166
|
+
/>
|
1167
|
+
<Button
|
1168
|
+
label="Launch modal with no scroll prevention"
|
1169
|
+
onClick={() => setModalOpen(2)}
|
1170
|
+
/>
|
1171
|
+
<Button
|
1172
|
+
label="Launch modal with custom scroll prevention"
|
1173
|
+
onClick={() => setModalOpen(3)}
|
1174
|
+
/>
|
1175
|
+
<div>
|
1176
|
+
{modalOpen === 1 && (
|
1177
|
+
<Modal
|
1178
|
+
closeButtonRef={modalCloseButtonRef}
|
1179
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
1180
|
+
>
|
1181
|
+
<ModalHeader>
|
1182
|
+
<ModalTitle>Modal with default scroll prevention</ModalTitle>
|
1183
|
+
<ModalCloseButton onClick={() => setModalOpen(null)} />
|
1184
|
+
</ModalHeader>
|
1185
|
+
<ModalBody>
|
1186
|
+
<ModalContent>
|
1187
|
+
<p>
|
1188
|
+
This Modal uses default scroll prevention on the document's
|
1189
|
+
<code>body</code> element.
|
1190
|
+
</p>
|
1191
|
+
</ModalContent>
|
1192
|
+
</ModalBody>
|
1193
|
+
<ModalFooter>
|
1194
|
+
<Button
|
1195
|
+
label="Acknowledge"
|
1196
|
+
onClick={() => setModalOpen(null)}
|
1197
|
+
ref={modalPrimaryButtonRef}
|
1198
|
+
/>
|
1199
|
+
<Button
|
1200
|
+
color="secondary"
|
1201
|
+
label="Close"
|
1202
|
+
onClick={() => setModalOpen(null)}
|
1203
|
+
priority="outline"
|
1204
|
+
ref={modalCloseButtonRef}
|
1205
|
+
/>
|
1206
|
+
</ModalFooter>
|
1207
|
+
</Modal>
|
1208
|
+
)}
|
1209
|
+
{modalOpen === 2 && (
|
1210
|
+
<Modal
|
1211
|
+
closeButtonRef={modalCloseButtonRef}
|
1212
|
+
preventScrollUnderneath="off"
|
1213
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
1214
|
+
>
|
1215
|
+
<ModalHeader>
|
1216
|
+
<ModalTitle>Modal with no scroll prevention</ModalTitle>
|
1217
|
+
<ModalCloseButton onClick={() => setModalOpen(null)} />
|
1218
|
+
</ModalHeader>
|
1219
|
+
<ModalBody>
|
1220
|
+
<ModalContent>
|
1221
|
+
<p>
|
1222
|
+
This Modal does not prevent scrolling.
|
1223
|
+
</p>
|
1224
|
+
</ModalContent>
|
1225
|
+
</ModalBody>
|
1226
|
+
<ModalFooter>
|
1227
|
+
<Button
|
1228
|
+
label="Acknowledge"
|
1229
|
+
onClick={() => setModalOpen(null)}
|
1230
|
+
ref={modalPrimaryButtonRef}
|
1231
|
+
/>
|
1232
|
+
<Button
|
1233
|
+
color="secondary"
|
1234
|
+
label="Close"
|
1235
|
+
onClick={() => setModalOpen(null)}
|
1236
|
+
priority="outline"
|
1237
|
+
ref={modalCloseButtonRef}
|
1238
|
+
/>
|
1239
|
+
</ModalFooter>
|
1240
|
+
</Modal>
|
1241
|
+
)}
|
1242
|
+
{modalOpen === 3 && (
|
1243
|
+
<Modal
|
1244
|
+
closeButtonRef={modalCloseButtonRef}
|
1245
|
+
preventScrollUnderneath={customScrollPreventionObject}
|
1246
|
+
primaryButtonRef={modalPrimaryButtonRef}
|
1247
|
+
>
|
1248
|
+
<ModalHeader>
|
1249
|
+
<ModalTitle>Modal with custom scroll prevention</ModalTitle>
|
1250
|
+
<ModalCloseButton onClick={() => setModalOpen(null)} />
|
1251
|
+
</ModalHeader>
|
1252
|
+
<ModalBody>
|
1253
|
+
<ModalContent>
|
1254
|
+
<p>
|
1255
|
+
This Modal uses provided custom functions to prevent scrolling
|
1256
|
+
and reset it on unmount.
|
1257
|
+
</p>
|
1258
|
+
</ModalContent>
|
1259
|
+
</ModalBody>
|
1260
|
+
<ModalFooter>
|
1261
|
+
<Button
|
1262
|
+
label="Acknowledge"
|
1263
|
+
onClick={() => setModalOpen(null)}
|
1264
|
+
ref={modalPrimaryButtonRef}
|
1265
|
+
/>
|
1266
|
+
<Button
|
1267
|
+
color="secondary"
|
1268
|
+
label="Close"
|
1269
|
+
onClick={() => setModalOpen(null)}
|
1270
|
+
priority="outline"
|
1271
|
+
ref={modalCloseButtonRef}
|
1272
|
+
/>
|
1273
|
+
</ModalFooter>
|
1274
|
+
</Modal>
|
1275
|
+
)}
|
1276
|
+
</div>
|
1277
|
+
</>
|
1278
|
+
);
|
1279
|
+
}}
|
1280
|
+
</Playground>
|
1009
1281
|
|
1010
1282
|
<!-- markdownlint-disable MD024 -->
|
1011
1283
|
|
@@ -1081,6 +1353,7 @@ accessibility.
|
|
1081
1353
|
| `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
|
1082
1354
|
| `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
|
1083
1355
|
|
1356
|
+
[nng-modal]: https://www.nngroup.com/articles/modal-nonmodal-dialog/
|
1084
1357
|
[React synthetic events]: https://reactjs.org/docs/events.html
|
1085
1358
|
[div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
|
1086
1359
|
[heading]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#attributes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
export const getSizeClassName = (modalSize, styles) => {
|
2
|
+
if (modalSize === 'small') {
|
3
|
+
return styles.isRootSizeSmall;
|
4
|
+
}
|
5
|
+
|
6
|
+
if (modalSize === 'medium') {
|
7
|
+
return styles.isRootSizeMedium;
|
8
|
+
}
|
9
|
+
|
10
|
+
if (modalSize === 'large') {
|
11
|
+
return styles.isRootSizeLarge;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (modalSize === 'fullscreen') {
|
15
|
+
return styles.isRootSizeFullscreen;
|
16
|
+
}
|
17
|
+
|
18
|
+
return styles.isRootSizeAuto;
|
19
|
+
};
|