@react-ui-org/react-ui 0.58.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +2 -11
  2. package/dist/react-ui.css +17 -17
  3. package/dist/react-ui.development.css +1228 -1051
  4. package/dist/react-ui.development.js +126 -66
  5. package/dist/react-ui.js +1 -1
  6. package/package.json +5 -5
  7. package/src/components/Alert/Alert.jsx +4 -4
  8. package/src/components/Alert/README.md +0 -26
  9. package/src/components/Alert/_settings.scss +1 -2
  10. package/src/components/Badge/Badge.jsx +2 -2
  11. package/src/components/Button/Button.jsx +2 -2
  12. package/src/components/ButtonGroup/ButtonGroup.jsx +2 -2
  13. package/src/components/Card/Card.jsx +6 -6
  14. package/src/components/Card/Card.module.scss +2 -2
  15. package/src/components/Card/CardBody.jsx +1 -1
  16. package/src/components/Card/CardFooter.jsx +1 -1
  17. package/src/components/Card/README.md +2 -21
  18. package/src/components/Card/_settings.scss +1 -2
  19. package/src/components/Card/_theme.scss +1 -0
  20. package/src/components/CheckboxField/CheckboxField.jsx +2 -2
  21. package/src/components/FileInputField/FileInputField.jsx +147 -21
  22. package/src/components/FileInputField/FileInputField.module.scss +87 -1
  23. package/src/components/FileInputField/README.md +83 -2
  24. package/src/components/FileInputField/_settings.scss +15 -0
  25. package/src/components/FormLayout/FormLayout.jsx +2 -2
  26. package/src/components/FormLayout/FormLayoutCustomField.jsx +2 -2
  27. package/src/components/FormLayout/README.md +1 -0
  28. package/src/components/Grid/Grid.jsx +1 -1
  29. package/src/components/Grid/Grid.module.scss +2 -2
  30. package/src/components/Grid/GridSpan.jsx +1 -1
  31. package/src/components/InputGroup/InputGroup.jsx +2 -2
  32. package/src/components/InputGroup/InputGroup.module.scss +3 -3
  33. package/src/components/InputGroup/README.md +1 -1
  34. package/src/components/Modal/Modal.jsx +117 -45
  35. package/src/components/Modal/Modal.module.scss +34 -18
  36. package/src/components/Modal/ModalBody.jsx +2 -2
  37. package/src/components/Modal/ModalBody.module.scss +18 -0
  38. package/src/components/Modal/ModalCloseButton.jsx +1 -1
  39. package/src/components/Modal/ModalContent.jsx +1 -1
  40. package/src/components/Modal/ModalFooter.jsx +2 -2
  41. package/src/components/Modal/ModalFooter.module.scss +6 -2
  42. package/src/components/Modal/ModalHeader.jsx +2 -2
  43. package/src/components/Modal/ModalHeader.module.scss +8 -1
  44. package/src/components/Modal/ModalTitle.jsx +1 -1
  45. package/src/components/Modal/README.md +391 -171
  46. package/src/components/Modal/_animations.scss +9 -0
  47. package/src/components/Modal/_helpers/dialogOnCancelHandler.js +28 -0
  48. package/src/components/Modal/_helpers/dialogOnClickHandler.js +46 -0
  49. package/src/components/Modal/_helpers/dialogOnCloseHandler.js +28 -0
  50. package/src/components/Modal/_helpers/dialogOnKeyDownHandler.js +62 -0
  51. package/src/components/Modal/_helpers/getPositionClassName.js +1 -1
  52. package/src/components/Modal/_hooks/useModalFocus.js +24 -91
  53. package/src/components/Modal/_settings.scss +4 -3
  54. package/src/components/Modal/_theme.scss +1 -0
  55. package/src/components/Paper/Paper.jsx +2 -2
  56. package/src/components/Popover/Popover.jsx +2 -2
  57. package/src/components/Popover/PopoverWrapper.jsx +1 -1
  58. package/src/components/Radio/Radio.jsx +2 -2
  59. package/src/components/ScrollView/ScrollView.jsx +2 -2
  60. package/src/components/SelectField/SelectField.jsx +2 -2
  61. package/src/components/Table/Table.jsx +1 -1
  62. package/src/components/Tabs/Tabs.jsx +1 -1
  63. package/src/components/Tabs/TabsItem.jsx +2 -2
  64. package/src/components/Text/Text.jsx +2 -2
  65. package/src/components/TextArea/TextArea.jsx +2 -2
  66. package/src/components/TextField/TextField.jsx +2 -2
  67. package/src/components/TextLink/TextLink.jsx +1 -1
  68. package/src/components/Toggle/Toggle.jsx +2 -2
  69. package/src/components/Toolbar/Toolbar.jsx +2 -2
  70. package/src/components/Toolbar/ToolbarGroup.jsx +2 -2
  71. package/src/components/Toolbar/ToolbarItem.jsx +2 -2
  72. package/src/helpers/classNames/README.md +65 -0
  73. package/src/helpers/classNames/classNames.js +11 -0
  74. package/src/helpers/classNames/index.js +1 -0
  75. package/src/helpers/transferProps/README.md +46 -0
  76. package/src/helpers/transferProps/index.js +1 -0
  77. package/src/index.js +3 -3
  78. package/src/styles/elements/_links.scss +2 -14
  79. package/src/styles/generic/_focus.scss +1 -1
  80. package/src/styles/theme/_form-fields.scss +5 -5
  81. package/src/styles/tools/_accessibility.scss +3 -5
  82. package/src/styles/tools/_collections.scss +3 -20
  83. package/src/styles/tools/_links.scss +17 -0
  84. package/src/styles/tools/form-fields/_box-field-elements.scss +21 -9
  85. package/src/styles/tools/form-fields/_box-field-layout.scss +2 -2
  86. package/src/styles/tools/form-fields/_box-field-sizes.scss +6 -10
  87. package/src/styles/tools/form-fields/_variants.scss +10 -10
  88. package/src/theme.scss +51 -1
  89. package/src/translations/en.js +5 -0
  90. package/src/styles/settings/_z-indexes.scss +0 -2
  91. package/src/utils/classNames.js +0 -8
  92. /package/src/{utils → helpers/transferProps}/transferProps.js +0 -0
@@ -92,11 +92,24 @@ See [API](#api) for all available options.
92
92
  - **Modal actions** should correspond to the modal purpose, too. E.g. “Delete”
93
93
  tells better what happens rather than “OK”.
94
94
 
95
- - Modal **automatically focuses the first non-disabled form field** by default
96
- which allows users to confirm the modal by hitting the enter key. When no
97
- field is found then the primary button (in the footer) is focused. To turn
95
+ - While native `<dialog>` (that is used under the hood) can be present in DOM,
96
+ modal is a more feature-rich component that provides more control over the
97
+ modal behavior and shall be **removed from DOM when closed**.
98
+
99
+ - Modal **automatically focuses the first non-disabled form field** by default.
100
+ When no field is found then the primary button (in the footer) is focused. To turn
98
101
  this feature off, set the `autofocus` prop to `false`.
99
102
 
103
+ - Modal **submits the form when the user presses the `Enter` key** . A click is
104
+ programmatically triggered on the primary button in this case. To turn this
105
+ feature off, set the `allowPrimaryActionOnEnterKey` prop to `false`.
106
+
107
+ - Modal **closes when the user presses the `Escape` key**. A click is
108
+ programmatically triggered on the close button in this case. To turn this
109
+ feature off, set the `allowCloseOnEscapeKey` prop to `false`. Modal can be
110
+ also **closed by clicking on the backdrop**. To turn this feature off,
111
+ set the `allowCloseOnBackdropClick` prop to `false`.
112
+
100
113
  - **Avoid stacking** of modals. While it may technically work, the modal is just
101
114
  not designed for that.
102
115
 
@@ -114,143 +127,8 @@ Modal is decomposed into the following components:
114
127
  - [ModalFooter](#modalfooter)
115
128
 
116
129
  Using different combinations, you can compose different kinds of modals,
117
- e.g. dialog modal, blocking modal, scrollable modal, etc.
118
-
119
- ```docoff-react-preview
120
- React.createElement(() => {
121
- const [modalOpen, setModalOpen] = React.useState(null);
122
- const modalPrimaryButtonRef = React.useRef();
123
- const modalCloseButtonRef = React.useRef();
124
- {/*
125
- The `preventScrollUnderneath` feature is necessary for Modals to work in
126
- React UI docs. You may not need it in your application.
127
- */}
128
- return (
129
- <GlobalPropsProvider globalProps={{
130
- Modal: { preventScrollUnderneath: window.document.documentElement }
131
- }}>
132
- <Button
133
- label="Launch blocking modal without title"
134
- onClick={() => {
135
- setModalOpen(1);
136
- setTimeout(() => setModalOpen(null), 2500);
137
- }}
138
- />
139
- <Button
140
- label="Launch blocking modal with title"
141
- onClick={() => {
142
- setModalOpen(2);
143
- setTimeout(() => setModalOpen(null), 3500);
144
- }}
145
- />
146
- <Button
147
- label="Launch modal as dialog"
148
- onClick={() => setModalOpen(3)}
149
- />
150
- <Button
151
- label="Launch modal as form"
152
- onClick={() => setModalOpen(4)}
153
- />
154
- <div>
155
- {modalOpen === 1 && (
156
- <Modal>
157
- <ModalBody>
158
- <ModalContent>
159
- <p className="text-center">
160
- Application is being loaded.
161
- <span className="d-inline-flex align-items-center animation-spin-counterclockwise">
162
- <rui-icon icon="loading" />
163
- </span>
164
- </p>
165
- </ModalContent>
166
- </ModalBody>
167
- </Modal>
168
- )}
169
- {modalOpen === 2 && (
170
- <Modal>
171
- <ModalHeader>
172
- <ModalTitle>Action finished</ModalTitle>
173
- </ModalHeader>
174
- <ModalBody>
175
- <ModalContent>
176
- <p>
177
- Action has been successfully finished.
178
- You will be redirected within a few seconds.
179
- </p>
180
- </ModalContent>
181
- </ModalBody>
182
- </Modal>
183
- )}
184
- {modalOpen === 3 && (
185
- <Modal
186
- closeButtonRef={modalCloseButtonRef}
187
- primaryButtonRef={modalPrimaryButtonRef}
188
- >
189
- <ModalHeader>
190
- <ModalTitle>Delete the user?</ModalTitle>
191
- <ModalCloseButton onClick={() => setModalOpen(false)} />
192
- </ModalHeader>
193
- <ModalBody>
194
- <ModalContent>
195
- <p>
196
- Do you really want to delete the user <code>admin</code>?
197
- This cannot be undone.
198
- </p>
199
- </ModalContent>
200
- </ModalBody>
201
- <ModalFooter>
202
- <Button
203
- color="danger"
204
- label="Delete"
205
- onClick={() => setModalOpen(false)}
206
- ref={modalPrimaryButtonRef}
207
- />
208
- <Button
209
- label="Close"
210
- onClick={() => setModalOpen(false)}
211
- priority="outline"
212
- ref={modalCloseButtonRef}
213
- />
214
- </ModalFooter>
215
- </Modal>
216
- )}
217
- {modalOpen === 4 && (
218
- <Modal
219
- closeButtonRef={modalCloseButtonRef}
220
- primaryButtonRef={modalPrimaryButtonRef}
221
- >
222
- <ModalHeader>
223
- <ModalTitle>Add new user</ModalTitle>
224
- <ModalCloseButton onClick={() => setModalOpen(false)} />
225
- </ModalHeader>
226
- <ModalBody>
227
- <ModalContent>
228
- <FormLayout fieldLayout="horizontal">
229
- <TextField label="Username" />
230
- <TextField label="Password" type="password" />
231
- </FormLayout>
232
- </ModalContent>
233
- </ModalBody>
234
- <ModalFooter>
235
- <Button
236
- label="Save"
237
- onClick={() => setModalOpen(false)}
238
- ref={modalPrimaryButtonRef}
239
- />
240
- <Button
241
- label="Close"
242
- onClick={() => setModalOpen(false)}
243
- priority="outline"
244
- ref={modalCloseButtonRef}
245
- />
246
- </ModalFooter>
247
- </Modal>
248
- )}
249
- </div>
250
- </GlobalPropsProvider>
251
- );
252
- });
253
- ```
130
+ e.g. dialog modal, [modal with form](#forms), [blocking modal](#interaction-blocking),
131
+ [scrollable modal](#scrolling-long-content), etc.
254
132
 
255
133
  ### ModalHeader
256
134
 
@@ -812,16 +690,106 @@ React.createElement(() => {
812
690
  });
813
691
  ```
814
692
 
815
- ## Keyboard Control
693
+ ## Color Variants
694
+
695
+ Modal can be colored using the `color` prop. The `color` prop implements the
696
+ [Feedback color collection](/docs/foundation/collections#colors)
697
+ and is applied to the border of the modal and the modal footer.
698
+
699
+ ```docoff-react-preview
700
+ React.createElement(() => {
701
+ const [modalOpen, setModalOpen] = React.useState(false);
702
+ const [modalColor, setModalColor] = React.useState('success');
703
+ const modalCloseButtonRef = React.useRef();
704
+ {/*
705
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
706
+ React UI docs. You may not need it in your application.
707
+ */}
708
+ return (
709
+ <GlobalPropsProvider globalProps={{
710
+ Modal: { preventScrollUnderneath: window.document.documentElement }
711
+ }}>
712
+ <Button
713
+ label="Launch modal with color options"
714
+ onClick={() => setModalOpen(true)}
715
+ />
716
+ <div>
717
+ {modalOpen && (
718
+ <Modal
719
+ closeButtonRef={modalCloseButtonRef}
720
+ color={modalColor}
721
+ >
722
+ <ModalHeader>
723
+ <ModalTitle>Modal color</ModalTitle>
724
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
725
+ </ModalHeader>
726
+ <ModalBody>
727
+ <ModalContent>
728
+ <Radio
729
+ label="Modal color"
730
+ onChange={(e) => setModalColor(e.target.value)}
731
+ options={[
732
+ {
733
+ label: 'success',
734
+ value: 'success',
735
+ },
736
+ {
737
+ label: 'warning',
738
+ value: 'warning',
739
+ },
740
+ {
741
+ label: 'danger',
742
+ value: 'danger',
743
+ },
744
+ {
745
+ label: 'info',
746
+ value: 'info',
747
+ },
748
+ {
749
+ label: 'help',
750
+ value: 'help',
751
+ },
752
+ {
753
+ label: 'note',
754
+ value: 'note',
755
+ },
756
+ ]}
757
+ value={modalColor}
758
+ />
759
+ </ModalContent>
760
+ </ModalBody>
761
+ <ModalFooter>
762
+ <Button
763
+ color={modalColor}
764
+ label="Close"
765
+ onClick={() => setModalOpen(false)}
766
+ ref={modalCloseButtonRef}
767
+ />
768
+ </ModalFooter>
769
+ </Modal>
770
+ )}
771
+ </div>
772
+ </GlobalPropsProvider>
773
+ );
774
+ });
775
+ ```
776
+
777
+ ## Mouse and Keyboard Control
816
778
 
817
779
  Modal can be controlled either by mouse or keyboard. To enhance user
818
- experience, primary action can be fired by pressing `Enter` key and the modal
819
- can be closed by pressing the `Escape` key.
780
+ experience, primary action can be fired by pressing `Enter` key and
781
+ the modal can be closed by pressing the `Escape` key. Modal can be
782
+ also closed by clicking on the backdrop.
820
783
 
821
784
  To enable it, you just need to pass a reference to the buttons using
822
- `primaryButtonRef` and `closeButtonRef` props on Modal. The advantage of passing
823
- a reference to the button is that if the button is disabled, the key press will
824
- not fire the event.
785
+ `primaryButtonRef` and `closeButtonRef` props on Modal. The advantage
786
+ of passing a reference to the button is that if the button is disabled,
787
+ the key press or the mouse click will not fire the event.
788
+
789
+ As `primaryButtonRef` and `closeButtonRef` are used for more than just
790
+ actions mentioned above, you can explicitly disable the default behavior
791
+ by changing `allowCloseOnBackdropClick`, `allowCloseOnEscapeKey` or
792
+ `allowPrimaryActionOnEnterKey` to `false`.
825
793
 
826
794
  👉 We strongly recommend using this feature together with Autofocus for a better
827
795
  user experience.
@@ -839,7 +807,241 @@ is focused.
839
807
  Autofocus is enabled by default, so if you want to control the focus of
840
808
  elements manually, set the `autoFocus` prop on Modal to `false`.
841
809
 
842
- ## Scrolling Long Content
810
+ ## Use Cases
811
+
812
+ ### Interaction blocking
813
+
814
+ Modal can be used to block user interaction while an action is being
815
+ performed.
816
+
817
+ ```docoff-react-preview
818
+ React.createElement(() => {
819
+ const [modalOpen, setModalOpen] = React.useState(null);
820
+ const modalPrimaryButtonRef = React.useRef();
821
+ const modalCloseButtonRef = React.useRef();
822
+ {/*
823
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
824
+ React UI docs. You may not need it in your application.
825
+ */}
826
+ return (
827
+ <GlobalPropsProvider globalProps={{
828
+ Modal: { preventScrollUnderneath: window.document.documentElement }
829
+ }}>
830
+ <Button
831
+ label="Launch blocking modal without title"
832
+ onClick={() => {
833
+ setModalOpen(1);
834
+ setTimeout(() => setModalOpen(null), 2500);
835
+ }}
836
+ />
837
+ <Button
838
+ label="Launch blocking modal with title"
839
+ onClick={() => {
840
+ setModalOpen(2);
841
+ setTimeout(() => setModalOpen(null), 3500);
842
+ }}
843
+ />
844
+ <div>
845
+ {modalOpen === 1 && (
846
+ <Modal>
847
+ <ModalBody>
848
+ <ModalContent>
849
+ <p className="text-center">
850
+ Application is being loaded.
851
+ <span className="d-inline-flex align-items-center animation-spin-counterclockwise">
852
+ <rui-icon icon="loading" />
853
+ </span>
854
+ </p>
855
+ </ModalContent>
856
+ </ModalBody>
857
+ </Modal>
858
+ )}
859
+ {modalOpen === 2 && (
860
+ <Modal>
861
+ <ModalHeader>
862
+ <ModalTitle>Action finished</ModalTitle>
863
+ </ModalHeader>
864
+ <ModalBody>
865
+ <ModalContent>
866
+ <p>
867
+ Action has been successfully finished.
868
+ You will be redirected within a few seconds.
869
+ </p>
870
+ </ModalContent>
871
+ </ModalBody>
872
+ </Modal>
873
+ )}
874
+ </div>
875
+ </GlobalPropsProvider>
876
+ );
877
+ });
878
+ ```
879
+
880
+ ### Forms
881
+
882
+ Modal can be used to display forms. It is recommended to use
883
+ [FormLayout](/components/FormLayout) component to layout form fields.
884
+
885
+ While we support only [controlled components][controlled-components],
886
+ and we encourage you to use them, it is possible to use native form and its
887
+ functionality inside the modal. This might be useful when you need to use
888
+ native form features like validation, submission, etc.
889
+
890
+ To do so, you need to set `allowPrimaryActionOnEnterKey` to `false` and remove
891
+ `onClick` from the primary button. Then, you need to set `form` attribute on the
892
+ primary button to the `id` of the form to connect it with the form.
893
+
894
+ ```docoff-react-preview
895
+ React.createElement(() => {
896
+ const [modalOpen, setModalOpen] = React.useState(null);
897
+ const modalPrimaryButtonRef = React.useRef();
898
+ const modalCloseButtonRef = React.useRef();
899
+ {/*
900
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
901
+ React UI docs. You may not need it in your application.
902
+ */}
903
+ return (
904
+ <GlobalPropsProvider globalProps={{
905
+ Modal: { preventScrollUnderneath: window.document.documentElement }
906
+ }}>
907
+ <Button
908
+ label="Launch modal as form"
909
+ onClick={() => setModalOpen(1)}
910
+ />
911
+ <Button
912
+ label="Launch modal as native form"
913
+ onClick={() => setModalOpen(2)}
914
+ />
915
+ <div>
916
+ {modalOpen === 1 && (
917
+ <Modal
918
+ closeButtonRef={modalCloseButtonRef}
919
+ primaryButtonRef={modalPrimaryButtonRef}
920
+ >
921
+ <ModalHeader>
922
+ <ModalTitle>Add new user</ModalTitle>
923
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
924
+ </ModalHeader>
925
+ <ModalBody>
926
+ <ModalContent>
927
+ <FormLayout fieldLayout="horizontal" labelWidth="limited">
928
+ <Toggle
929
+ label="Enabled"
930
+ />
931
+ <TextField label="Username" required />
932
+ <TextField label="Password" type="password" />
933
+ <CheckboxField label="Force password on login" />
934
+ <Radio
935
+ label="Type of collaboration"
936
+ options={[
937
+ { label: 'Internal', value: 'internal'},
938
+ { label: 'External', value: 'external'},
939
+ ]}
940
+ />
941
+ <SelectField
942
+ label="Role"
943
+ options={[
944
+ { label: 'Programmer', value: 'programmer' },
945
+ { label: 'Team leader', value: 'team-leader' },
946
+ { label: 'Project manager', value: 'project-manager' },
947
+ ]}
948
+ />
949
+ <FileInputField label="Photo" onFilesChanged={() => {}} />
950
+ <TextArea
951
+ label="Additional info"
952
+ helpText={<p>Enter key is used for new line,<br />so <strong>Enter won't submit the form</strong>.</p>}
953
+ />
954
+ </FormLayout>
955
+ </ModalContent>
956
+ </ModalBody>
957
+ <ModalFooter>
958
+ <Button
959
+ label="Save"
960
+ onClick={() => setModalOpen(false)}
961
+ ref={modalPrimaryButtonRef}
962
+ />
963
+ <Button
964
+ label="Close"
965
+ onClick={() => setModalOpen(false)}
966
+ priority="outline"
967
+ ref={modalCloseButtonRef}
968
+ />
969
+ </ModalFooter>
970
+ </Modal>
971
+ )}
972
+ {modalOpen === 2 && (
973
+ <Modal
974
+ allowPrimaryActionOnEnterKey={false}
975
+ closeButtonRef={modalCloseButtonRef}
976
+ onCancel={(e) => {
977
+ console.log('cancel', e);
978
+ }}
979
+ onClose={(e) => {
980
+ console.log('close', e);
981
+ }}
982
+ primaryButtonRef={modalPrimaryButtonRef}
983
+ >
984
+ <ModalHeader>
985
+ <ModalTitle>Add new user using native form</ModalTitle>
986
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
987
+ </ModalHeader>
988
+ <ModalBody>
989
+ <ModalContent>
990
+ <form method="dialog" id="native-form">
991
+ <FormLayout fieldLayout="horizontal" labelWidth="limited">
992
+ <Toggle
993
+ label="Enabled"
994
+ />
995
+ <TextField label="Username" required />
996
+ <TextField label="Password" type="password" />
997
+ <CheckboxField label="Force password on login" />
998
+ <Radio
999
+ label="Type of collaboration"
1000
+ options={[
1001
+ { label: 'Internal', value: 'internal'},
1002
+ { label: 'External', value: 'external'},
1003
+ ]}
1004
+ />
1005
+ <SelectField
1006
+ label="Role"
1007
+ options={[
1008
+ { label: 'Programmer', value: 'programmer' },
1009
+ { label: 'Team leader', value: 'team-leader' },
1010
+ { label: 'Project manager', value: 'project-manager' },
1011
+ ]}
1012
+ />
1013
+ <FileInputField label="Photo" />
1014
+ <TextArea
1015
+ label="Additional info"
1016
+ helpText={<p>Enter key is used for new line,<br />so <strong>Enter won't submit the form</strong>.</p>}
1017
+ />
1018
+ </FormLayout>
1019
+ </form>
1020
+ </ModalContent>
1021
+ </ModalBody>
1022
+ <ModalFooter>
1023
+ <Button
1024
+ form="native-form"
1025
+ label="Save"
1026
+ ref={modalPrimaryButtonRef}
1027
+ type="submit"
1028
+ />
1029
+ <Button
1030
+ label="Close"
1031
+ onClick={() => setModalOpen(false)}
1032
+ priority="outline"
1033
+ ref={modalCloseButtonRef}
1034
+ />
1035
+ </ModalFooter>
1036
+ </Modal>
1037
+ )}
1038
+ </div>
1039
+ </GlobalPropsProvider>
1040
+ );
1041
+ });
1042
+ ```
1043
+
1044
+ ### Scrolling Long Content
843
1045
 
844
1046
  When modals become too long for the user's viewport or device, they scroll
845
1047
  independent of the page itself. This can be done in three ways using the
@@ -1004,7 +1206,7 @@ React.createElement(() => {
1004
1206
  });
1005
1207
  ```
1006
1208
 
1007
- ### Long Content and Autofocus
1209
+ #### Long Content and Autofocus
1008
1210
 
1009
1211
  👉 If you wrap ModalContent with ScrollView, you may want to turn `autoFocus`
1010
1212
  off to prevent the modal from scrolling to the end immediately after being
@@ -1019,8 +1221,7 @@ can specify **any HTML attribute you like.** All attributes that don't
1019
1221
  interfere with the API of the React component and that aren't filtered out by
1020
1222
  [`transferProps`](/docs/js-helpers/transferProps) helper are forwarded to:
1021
1223
 
1022
- - the `<div>` HTML element in case of the `Modal` component. This `<div>` is not
1023
- the root, but its first child which represents the modal window.
1224
+ - the `<dialog>` HTML element in case of the `Modal` component.
1024
1225
  - the root `<div>` HTML element in case of `ModalHeader`, `ModalBody`, `ModalContent`
1025
1226
  and `ModalFooter` components.
1026
1227
  - the heading (e.g. `<h1>`) HTML element in case of the `ModalTitle` component.
@@ -1031,6 +1232,7 @@ accessibility.
1031
1232
 
1032
1233
  👉 For the full list of supported attributes refer to:
1033
1234
 
1235
+ - [`<dialog>` HTML element attributes][dialog-attributes]{:target="_blank"}
1034
1236
  - [`<div>` HTML element attributes][div-attributes]{:target="_blank"}
1035
1237
  - [`<h1>`-`<h6>` HTML element attributes][heading-attributes]{:target="_blank"}
1036
1238
  - [`<button>` HTML element attributes][button-attributes]{:target="_blank"}
@@ -1066,29 +1268,47 @@ accessibility.
1066
1268
 
1067
1269
  ## Theming
1068
1270
 
1069
- | Custom Property | Description |
1070
- |------------------------------------------------------|---------------------------------------------------------------|
1071
- | `--rui-Modal__padding-x` | Inline padding of individual modal components |
1072
- | `--rui-Modal__padding-y` | Block padding of individual modal components |
1073
- | `--rui-Modal__background` | Modal background (including `url()` or gradient) |
1074
- | `--rui-Modal__box-shadow` | Modal box shadow |
1075
- | `--rui-Modal__separator__width` | Width of separator between modal header, body, and footer |
1076
- | `--rui-Modal__separator__color` | Color of separator between modal header, body, and footer |
1077
- | `--rui-Modal__outer-spacing-xs` | Spacing around modal, `xs` screen size |
1078
- | `--rui-Modal__outer-spacing-sm` | Spacing around modal, `sm` screen size and bigger |
1079
- | `--rui-Modal__header__gap` | Modal header gap between children |
1080
- | `--rui-Modal__footer__background` | Modal footer background (including `url()` or gradient) |
1081
- | `--rui-Modal__footer__gap` | Modal footer gap between children |
1082
- | `--rui-Modal__backdrop__background` | Modal backdrop background (including `url()` or gradient) |
1083
- | `--rui-Modal--auto__min-width` | Min width of auto-sized modal (when enough screen estate) |
1084
- | `--rui-Modal--auto__max-width` | Max width of auto-sized modal (when enough screen estate) |
1085
- | `--rui-Modal--small__width` | Width of small modal |
1086
- | `--rui-Modal--medium__width` | Width of medium modal |
1087
- | `--rui-Modal--large__width` | Width of large modal |
1088
- | `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
1089
- | `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
1271
+ | Custom Property | Description |
1272
+ |------------------------------------------------------|-------------------------------------------------------------|
1273
+ | `--rui-Modal__padding-x` | Inline padding of individual modal components |
1274
+ | `--rui-Modal__padding-y` | Block padding of individual modal components |
1275
+ | `--rui-Modal__background` | Modal background (including `url()` or gradient) |
1276
+ | `--rui-Modal__box-shadow` | Modal box shadow |
1277
+ | `--rui-Modal__separator__width` | Width of separator between modal header, body, and footer |
1278
+ | `--rui-Modal__separator__color` | Color of separator between modal header, body, and footer |
1279
+ | `--rui-Modal__outer-spacing-xs` | Spacing around modal, `xs` screen size |
1280
+ | `--rui-Modal__outer-spacing-sm` | Spacing around modal, `sm` screen size and bigger |
1281
+ | `--rui-Modal__header__gap` | Modal header gap between children |
1282
+ | `--rui-Modal__footer__background` | Modal footer background (including `url()` or gradient) |
1283
+ | `--rui-Modal__footer__gap` | Modal footer gap between children |
1284
+ | `--rui-Modal__backdrop__background` | Modal backdrop background (including `url()` or gradient) |
1285
+ | `--rui-Modal--auto__min-width` | Min width of auto-sized modal (when enough screen estate) |
1286
+ | `--rui-Modal--auto__max-width` | Max width of auto-sized modal (when enough screen estate) |
1287
+ | `--rui-Modal--small__width` | Width of small modal |
1288
+ | `--rui-Modal--medium__width` | Width of medium modal |
1289
+ | `--rui-Modal--large__width` | Width of large modal |
1290
+ | `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
1291
+ | `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
1292
+ | `--rui-Modal__animation__duration` | Duration of animation used (when opening modal) |
1293
+
1294
+ ### Theming Variants
1295
+
1296
+ It's possible to adjust the theme of specific color variant. Naming convention
1297
+ looks as follows:
1298
+
1299
+ `--rui-Modal--<COLOR>__<PROPERTY>`
1300
+
1301
+ Where:
1302
+
1303
+ - `<COLOR>` is a value from supported
1304
+ [color collections](/docs/foundation/collections#colors)
1305
+ (check [color variants](#color-variants) and [API](#api) to see which
1306
+ collections are supported),
1307
+ - `<PROPERTY>` is one of `border-color` or `background-color`.
1090
1308
 
1091
1309
  [button-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes
1310
+ [controlled-components]: /docs/getting-started/usage#foundation-css
1311
+ [dialog-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog#attributes
1092
1312
  [div-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
1093
1313
  [heading-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#attributes
1094
1314
  [React common props]: https://react.dev/reference/react-dom/components/common#common-props
@@ -0,0 +1,9 @@
1
+ @keyframes fade-in {
2
+ 0% {
3
+ opacity: 0;
4
+ }
5
+
6
+ 100% {
7
+ opacity: 1;
8
+ }
9
+ }
@@ -0,0 +1,28 @@
1
+ // Disable coverage for the following function
2
+ /* istanbul ignore next */
3
+
4
+ /**
5
+ * Handles the cancel event of the dialog which is fired when the user presses the Escape key or triggers cancel event
6
+ * by native dialog mechanism.
7
+ *
8
+ * It prevents the default behaviour of the native dialog and closes the dialog manually by clicking the close button,
9
+ * if the close button is not disabled.
10
+ *
11
+ * @param e
12
+ * @param closeButtonRef
13
+ * @param onCancelHandler
14
+ */
15
+ export const dialogOnCancelHandler = (e, closeButtonRef, onCancelHandler = undefined) => {
16
+ // Prevent the default behaviour of the event as we want to close dialog manually.
17
+ e.preventDefault();
18
+
19
+ // If the close button is not disabled, close the modal.
20
+ if (closeButtonRef?.current != null && closeButtonRef?.current?.disabled === false) {
21
+ closeButtonRef.current.click();
22
+ }
23
+
24
+ // This is a custom handler that is passed as a prop to the Modal component
25
+ if (onCancelHandler) {
26
+ onCancelHandler(e);
27
+ }
28
+ };