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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. package/.nvmrc +1 -1
  2. package/dist/react-ui.css +17 -17
  3. package/dist/react-ui.development.css +2551 -831
  4. package/dist/react-ui.development.js +106 -66
  5. package/dist/react-ui.js +1 -1
  6. package/package.json +13 -2
  7. package/src/CNAME +1 -0
  8. package/src/components/Alert/Alert.jsx +5 -6
  9. package/src/components/Alert/Alert.module.scss +12 -34
  10. package/src/components/Alert/README.md +28 -15
  11. package/src/components/Alert/_settings.scss +5 -0
  12. package/src/components/Alert/_theme.scss +0 -43
  13. package/src/components/Badge/Badge.jsx +5 -3
  14. package/src/components/Badge/Badge.module.scss +29 -74
  15. package/src/components/Badge/README.md +19 -2
  16. package/src/components/Badge/_settings.scss +8 -0
  17. package/src/components/Button/Button.jsx +4 -3
  18. package/src/components/Button/Button.module.scss +183 -2
  19. package/src/components/Button/README.md +8 -6
  20. package/src/components/Button/_settings.scss +8 -3
  21. package/src/components/Button/_theme.scss +0 -3
  22. package/src/components/Button/_tools.scss +7 -71
  23. package/src/components/ButtonGroup/ButtonGroup.jsx +2 -2
  24. package/src/components/Card/Card.jsx +3 -2
  25. package/src/components/Card/Card.module.scss +13 -33
  26. package/src/components/Card/CardBody.jsx +1 -1
  27. package/src/components/Card/CardFooter.jsx +1 -1
  28. package/src/components/Card/README.md +28 -6
  29. package/src/components/Card/_settings.scss +5 -0
  30. package/src/components/Card/_theme.scss +0 -43
  31. package/src/components/CheckboxField/CheckboxField.jsx +9 -3
  32. package/src/components/CheckboxField/README.md +110 -5
  33. package/src/components/FileInputField/FileInputField.jsx +1 -1
  34. package/src/components/FormLayout/FormLayout.jsx +1 -1
  35. package/src/components/FormLayout/FormLayoutCustomField.jsx +1 -1
  36. package/src/components/Grid/Grid.jsx +1 -1
  37. package/src/components/Grid/Grid.module.scss +9 -2
  38. package/src/components/Grid/GridSpan.jsx +1 -1
  39. package/src/components/InputGroup/InputGroup.jsx +2 -2
  40. package/src/components/InputGroup/InputGroup.module.scss +9 -5
  41. package/src/components/Modal/Modal.jsx +1 -1
  42. package/src/components/Modal/ModalBody.jsx +1 -1
  43. package/src/components/Modal/ModalCloseButton.jsx +3 -5
  44. package/src/components/Modal/ModalContent.jsx +1 -1
  45. package/src/components/Modal/ModalFooter.jsx +1 -1
  46. package/src/components/Modal/ModalHeader.jsx +1 -1
  47. package/src/components/Modal/ModalTitle.jsx +1 -1
  48. package/src/components/Modal/README.md +18 -18
  49. package/src/components/Paper/Paper.jsx +1 -1
  50. package/src/components/Popover/Popover.jsx +58 -13
  51. package/src/components/Popover/Popover.module.scss +51 -23
  52. package/src/components/Popover/PopoverWrapper.jsx +1 -1
  53. package/src/components/Popover/README.md +60 -3
  54. package/src/components/Popover/_helpers/cleanPlacementStyle.js +20 -0
  55. package/src/components/Popover/_theme.scss +4 -2
  56. package/src/components/Radio/README.md +103 -0
  57. package/src/components/Radio/Radio.jsx +9 -3
  58. package/src/components/Radio/Radio.module.scss +4 -0
  59. package/src/components/ScrollView/ScrollView.jsx +3 -5
  60. package/src/components/SelectField/README.md +103 -0
  61. package/src/components/SelectField/SelectField.jsx +9 -3
  62. package/src/components/Table/Table.jsx +1 -1
  63. package/src/components/Tabs/Tabs.jsx +1 -1
  64. package/src/components/Tabs/TabsItem.jsx +1 -1
  65. package/src/components/Text/Text.jsx +1 -1
  66. package/src/components/TextArea/TextArea.jsx +1 -1
  67. package/src/components/TextField/README.md +14 -2
  68. package/src/components/TextField/TextField.jsx +1 -1
  69. package/src/components/TextLink/README.md +10 -3
  70. package/src/components/TextLink/TextLink.jsx +1 -1
  71. package/src/components/TextLink/_theme.scss +3 -3
  72. package/src/components/Toggle/README.md +83 -1
  73. package/src/components/Toggle/Toggle.jsx +9 -3
  74. package/src/components/Toolbar/Toolbar.jsx +1 -1
  75. package/src/components/Toolbar/ToolbarGroup.jsx +1 -1
  76. package/src/components/Toolbar/ToolbarItem.jsx +1 -1
  77. package/src/components/_helpers/getRootPriorityClassName.js +1 -1
  78. package/src/components/_helpers/resolveContextOrProp.js +6 -3
  79. package/src/index.js +3 -2
  80. package/src/providers/globalProps/GlobalPropsContext.jsx +5 -0
  81. package/src/providers/globalProps/GlobalPropsProvider.jsx +33 -0
  82. package/src/providers/globalProps/index.js +3 -0
  83. package/src/{provider → providers/globalProps}/withGlobalProps.jsx +16 -16
  84. package/src/providers/translations/TranslationsContext.jsx +6 -0
  85. package/src/providers/translations/TranslationsProvider.jsx +33 -0
  86. package/src/providers/translations/index.js +2 -0
  87. package/src/styles/elements/_links.scss +7 -2
  88. package/src/styles/settings/_collections.scss +9 -0
  89. package/src/styles/theme/_form-fields.scss +19 -0
  90. package/src/styles/theme/_links.scss +4 -3
  91. package/src/styles/tools/_collections.scss +265 -0
  92. package/src/styles/tools/_string.scss +5 -2
  93. package/src/styles/tools/form-fields/_box-field-layout.scss +7 -1
  94. package/src/styles/tools/form-fields/_foundation.scss +6 -4
  95. package/src/styles/tools/form-fields/_variants.scss +5 -1
  96. package/src/theme.scss +66 -1
  97. package/src/components/Alert/_tools.scss +0 -10
  98. package/src/components/Button/_base.scss +0 -156
  99. package/src/components/Button/_priorities.scss +0 -149
  100. package/src/components/Card/_tools.scss +0 -10
  101. package/src/provider/RUIContext.jsx +0 -9
  102. package/src/provider/RUIProvider.jsx +0 -42
  103. package/src/provider/index.js +0 -3
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
@@ -15,6 +15,7 @@ export const CheckboxField = React.forwardRef((props, ref) => {
15
15
  isLabelVisible,
16
16
  label,
17
17
  labelPosition,
18
+ renderAsRequired,
18
19
  required,
19
20
  validationState,
20
21
  validationText,
@@ -30,7 +31,7 @@ export const CheckboxField = React.forwardRef((props, ref) => {
30
31
  context && context.layout === 'horizontal' ? styles.isRootLayoutHorizontal : styles.isRootLayoutVertical,
31
32
  labelPosition === 'before' && styles.hasRootLabelBefore,
32
33
  disabled && styles.isRootDisabled,
33
- required && styles.isRootRequired,
34
+ (renderAsRequired || required) && styles.isRootRequired,
34
35
  getRootValidationStateClassName(validationState, styles),
35
36
  )}
36
37
  htmlFor={id}
@@ -82,6 +83,7 @@ CheckboxField.defaultProps = {
82
83
  id: undefined,
83
84
  isLabelVisible: true,
84
85
  labelPosition: 'after',
86
+ renderAsRequired: false,
85
87
  required: false,
86
88
  validationState: null,
87
89
  validationText: null,
@@ -120,7 +122,11 @@ CheckboxField.propTypes = {
120
122
  */
121
123
  labelPosition: PropTypes.oneOf(['before', 'after']),
122
124
  /**
123
- * If `true`, the input will be required.
125
+ * If `true`, the input will be rendered as if it was required.
126
+ */
127
+ renderAsRequired: PropTypes.bool,
128
+ /**
129
+ * If `true`, the input will be made and rendered as required, regardless of the `renderAsRequired` prop.
124
130
  */
125
131
  required: PropTypes.bool,
126
132
  /**
@@ -18,7 +18,13 @@ React.createElement(() => {
18
18
  return (
19
19
  <CheckboxField
20
20
  checked={agree}
21
- label="I agree"
21
+ label={(
22
+ <>
23
+ I have read and agree with
24
+ {' '}
25
+ <TextLink href="#" label="terms and conditions" />
26
+ </>
27
+ )}
22
28
  onChange={() => setAgree(!agree)}
23
29
  />
24
30
  );
@@ -132,20 +138,44 @@ React.createElement(() => {
132
138
  <>
133
139
  <CheckboxField
134
140
  checked={agree}
135
- label="I have read and agree with terms and conditions"
141
+ label={(
142
+ <>
143
+ I have read and agree with
144
+ {' '}
145
+ <TextLink href="#" label="terms and conditions" />
146
+ </>
147
+ )}
136
148
  onChange={() => setAgree(!agree)}
137
149
  validationState="valid"
138
150
  />
139
151
  <CheckboxField
140
152
  checked={agree}
141
- label="I have read and agree with terms and conditions"
153
+ label={(
154
+ <>
155
+ I have read and agree with
156
+ {' '}
157
+ <TextLink href="#" label="terms and conditions" />
158
+ </>
159
+ )}
142
160
  onChange={() => setAgree(!agree)}
143
161
  validationState="warning"
144
- validationText="Please wait 10 minutes until we verify your data."
162
+ validationText={(
163
+ <>
164
+ Please wait 10 minutes until we verify your data.
165
+ {' '}
166
+ <TextLink href="#" label="Cancel" />
167
+ </>
168
+ )}
145
169
  />
146
170
  <CheckboxField
147
171
  checked={agree}
148
- label="I have read and agree with terms and conditions"
172
+ label={(
173
+ <>
174
+ I have read and agree with
175
+ {' '}
176
+ <TextLink href="#" label="terms and conditions" />
177
+ </>
178
+ )}
149
179
  onChange={() => setAgree(!agree)}
150
180
  required
151
181
  validationState="invalid"
@@ -156,6 +186,81 @@ React.createElement(() => {
156
186
  });
157
187
  ```
158
188
 
189
+ ### Required State
190
+
191
+ The required state indicates that the input is mandatory. Required fields
192
+ display an asterisk `*` after the label by default.
193
+
194
+ ```docoff-react-preview
195
+ React.createElement(() => {
196
+ const [agree, setAgree] = React.useState(true);
197
+ return (
198
+ <CheckboxField
199
+ checked={agree}
200
+ label="I agree"
201
+ onChange={() => setAgree(!agree)}
202
+ required
203
+ />
204
+ );
205
+ });
206
+ ```
207
+
208
+ #### Styling the Required State
209
+
210
+ All form fields in React UI can be
211
+ [styled](/docs/customize/theming/forms/#required-state)
212
+ to indicate the required state.
213
+
214
+ However, you may find yourself in a situation where a form field is valid in
215
+ both checked and unchecked states, for example to turn on or off a feature.
216
+ If your project uses the label color as the primary means to indicate the
217
+ required state of input fields and the usual asterisk `*` is omitted, you may
218
+ want to keep the label color consistent for both states to avoid confusion.
219
+
220
+ For this edge case, there is the `renderAsRequired` prop:
221
+
222
+ ```docoff-react-preview
223
+ React.createElement(() => {
224
+ const [optional, setOptional] = React.useState(false);
225
+ const [renderAsRequired, setRenderAsRequired] = React.useState(false);
226
+ return (
227
+ <React.Fragment>
228
+ <style>
229
+ {`
230
+ .example {
231
+ display: flex;
232
+ flex-wrap: wrap;
233
+ gap: 1rem 0.5rem;
234
+ }
235
+
236
+ .example--themed-form-fields {
237
+ --rui-FormField__label__color: var(--rui-color-text-secondary);
238
+ --rui-FormField--required__label__color: var(--rui-color-text-primary);
239
+ --rui-FormField--required__sign: '';
240
+ }
241
+ `}
242
+ </style>
243
+ <div class="example example--themed-form-fields">
244
+ <CheckboxField
245
+ checked={optional}
246
+ label="This field is optional"
247
+ onChange={() => setOptional(!optional)}
248
+ />
249
+ <CheckboxField
250
+ checked={renderAsRequired}
251
+ label="This field is optional but looks like required"
252
+ onChange={() => setRenderAsRequired(!renderAsRequired)}
253
+ renderAsRequired
254
+ />
255
+ </div>
256
+ </React.Fragment>
257
+ );
258
+ });
259
+ ```
260
+
261
+ It renders the field as if it was required, but doesn't add the `required`
262
+ attribute to the actual input.
263
+
159
264
  ### Disabled State
160
265
 
161
266
  Disabled state makes the input unavailable.
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useMemo } from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { transferProps } from '../../utils/transferProps';
5
5
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
6
  import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
@@ -19,6 +19,9 @@
19
19
  // `--rui-local-<PROPERTY>: var(--rui-local-<PROPERTY>-sm, var(--rui-local-<PROPERTY>-xs, <INITIAL FALLBACK>))`
20
20
  //
21
21
  // 2. Apply custom property value that is defined within current breakpoint, see 1.
22
+ //
23
+ // 3. Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values as
24
+ // empty. That makes the other value of the shorthand property unexpectedly used for both axes.
22
25
 
23
26
  @use "sass:map";
24
27
  @use "../../styles/tools/spacing";
@@ -35,8 +38,12 @@
35
38
  grid-template-rows: var(--rui-local-rows); // 2.
36
39
  grid-auto-flow: var(--rui-local-auto-flow); // 2.
37
40
  grid-gap: var(--rui-local-row-gap) var(--rui-local-column-gap); // 2.
38
- place-content: var(--rui-local-align-content) var(--rui-local-justify-content); // 2.
39
- place-items: var(--rui-local-align-items) var(--rui-local-justify-items); // 2.
41
+ // stylelint-disable declaration-block-no-redundant-longhand-properties -- 3.
42
+ align-content: var(--rui-local-align-content); // 2.
43
+ align-items: var(--rui-local-align-items); // 2.
44
+ justify-content: var(--rui-local-justify-content); // 2.
45
+ justify-items: var(--rui-local-justify-items); // 2.
46
+ // stylelint-enable declaration-block-no-redundant-longhand-properties
40
47
  }
41
48
 
42
49
  // stylelint-disable-next-line selector-max-universal -- Reset any previously added margins.
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { transferProps } from '../../utils/transferProps';
5
5
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
6
  import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
@@ -3,8 +3,7 @@ import React, {
3
3
  useContext,
4
4
  useMemo,
5
5
  } from 'react';
6
- import { Text } from '../Text';
7
- import { withGlobalProps } from '../../provider';
6
+ import { withGlobalProps } from '../../providers/globalProps';
8
7
  import { classNames } from '../../utils/classNames';
9
8
  import { transferProps } from '../../utils/transferProps';
10
9
  import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
@@ -12,6 +11,7 @@ import { getRootValidationStateClassName } from '../_helpers/getRootValidationSt
12
11
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
13
12
  import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
14
13
  import { FormLayoutContext } from '../FormLayout';
14
+ import { Text } from '../Text';
15
15
  import { InputGroupContext } from './InputGroupContext';
16
16
  import styles from './InputGroup.module.scss';
17
17
 
@@ -1,7 +1,9 @@
1
1
  // 1. The class name is intentionally singular because it's targeted by other mixins too.
2
2
  // 2. Use a block-level display mode to prevent extra white space below grouped inputs in Safari.
3
- // 3. Prevent individual inputs from overlapping inside narrow containers.
4
- // 4. Legends are tricky to style, let's use a `div` instead.
3
+ // 3. Let wide input groups honor the minimum input width and overflow horizontally without wrapping and distorting
4
+ // the inputs.
5
+ // 4. Prevent individual inputs from overlapping inside narrow containers.
6
+ // 5. Legends are tricky to style, let's use a `div` instead.
5
7
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#styling_with_css
6
8
 
7
9
  @use "../../styles/tools/form-fields/box-field-elements";
@@ -19,12 +21,12 @@
19
21
  @include foundation.fieldset();
20
22
  }
21
23
 
22
- // 4.
24
+ // 5.
23
25
  .legend {
24
26
  @include accessibility.hide-text();
25
27
  }
26
28
 
27
- // 4.
29
+ // 5.
28
30
  .label {
29
31
  @include foundation.label();
30
32
  }
@@ -63,11 +65,13 @@
63
65
  .isRootLayoutVertical,
64
66
  .isRootLayoutHorizontal {
65
67
  @include box-field-layout.vertical();
68
+
69
+ max-width: none; // 3.
66
70
  }
67
71
 
68
72
  .isRootLayoutVertical .field,
69
73
  .isRootLayoutHorizontal .field {
70
- max-width: none; // 3.
74
+ max-width: none; // 4.
71
75
  }
72
76
 
73
77
  .isRootLayoutHorizontal {
@@ -1,7 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useRef } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { withGlobalProps } from '../../provider';
4
+ import { withGlobalProps } from '../../providers/globalProps';
5
5
  import { classNames } from '../../utils/classNames';
6
6
  import { transferProps } from '../../utils/transferProps';
7
7
  import { getPositionClassName } from './_helpers/getPositionClassName';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
@@ -1,9 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
- import {
4
- RUIContext,
5
- withGlobalProps,
6
- } from '../../provider';
3
+ import { TranslationsContext } from '../../providers/translations';
4
+ import { withGlobalProps } from '../../providers/globalProps';
7
5
  import { transferProps } from '../../utils/transferProps';
8
6
  import styles from './ModalCloseButton.module.scss';
9
7
 
@@ -13,7 +11,7 @@ export const ModalCloseButton = React.forwardRef((props, ref) => {
13
11
  ...restProps
14
12
  } = props;
15
13
 
16
- const { translations } = useContext(RUIContext);
14
+ const translations = useContext(TranslationsContext);
17
15
 
18
16
  return (
19
17
  <button
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { transferProps } from '../../utils/transferProps';
5
5
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
6
  import styles from './ModalContent.module.scss';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { transferProps } from '../../utils/transferProps';
5
5
  import styles from './ModalTitle.module.scss';
6
6
 
@@ -30,7 +30,7 @@ React.createElement(() => {
30
30
  React UI docs. You may not need it in your application.
31
31
  */}
32
32
  return (
33
- <RUIProvider globalProps={{
33
+ <GlobalPropsProvider globalProps={{
34
34
  Modal: { preventScrollUnderneath: window.document.documentElement }
35
35
  }}>
36
36
  <Button
@@ -72,7 +72,7 @@ React.createElement(() => {
72
72
  </Modal>
73
73
  )}
74
74
  </div>
75
- </RUIProvider>
75
+ </GlobalPropsProvider>
76
76
  );
77
77
  });
78
78
  ```
@@ -126,7 +126,7 @@ React.createElement(() => {
126
126
  React UI docs. You may not need it in your application.
127
127
  */}
128
128
  return (
129
- <RUIProvider globalProps={{
129
+ <GlobalPropsProvider globalProps={{
130
130
  Modal: { preventScrollUnderneath: window.document.documentElement }
131
131
  }}>
132
132
  <Button
@@ -247,7 +247,7 @@ React.createElement(() => {
247
247
  </Modal>
248
248
  )}
249
249
  </div>
250
- </RUIProvider>
250
+ </GlobalPropsProvider>
251
251
  );
252
252
  });
253
253
  ```
@@ -281,7 +281,7 @@ React.createElement(() => {
281
281
  React UI docs. You may not need it in your application.
282
282
  */}
283
283
  return (
284
- <RUIProvider globalProps={{
284
+ <GlobalPropsProvider globalProps={{
285
285
  Modal: { preventScrollUnderneath: window.document.documentElement }
286
286
  }}>
287
287
  <Button
@@ -374,7 +374,7 @@ React.createElement(() => {
374
374
  </Modal>
375
375
  )}
376
376
  </div>
377
- </RUIProvider>
377
+ </GlobalPropsProvider>
378
378
  );
379
379
  });
380
380
  ```
@@ -415,7 +415,7 @@ React.createElement(() => {
415
415
  React UI docs. You may not need it in your application.
416
416
  */}
417
417
  return (
418
- <RUIProvider globalProps={{
418
+ <GlobalPropsProvider globalProps={{
419
419
  Modal: { preventScrollUnderneath: window.document.documentElement }
420
420
  }}>
421
421
  <Button
@@ -517,7 +517,7 @@ React.createElement(() => {
517
517
  </Modal>
518
518
  )}
519
519
  </div>
520
- </RUIProvider>
520
+ </GlobalPropsProvider>
521
521
  );
522
522
  });
523
523
  ```
@@ -538,7 +538,7 @@ React.createElement(() => {
538
538
  React UI docs. You may not need it in your application.
539
539
  */}
540
540
  return (
541
- <RUIProvider globalProps={{
541
+ <GlobalPropsProvider globalProps={{
542
542
  Modal: { preventScrollUnderneath: window.document.documentElement }
543
543
  }}>
544
544
  <Button
@@ -605,7 +605,7 @@ React.createElement(() => {
605
605
  </Modal>
606
606
  )}
607
607
  </div>
608
- </RUIProvider>
608
+ </GlobalPropsProvider>
609
609
  );
610
610
  });
611
611
  ```
@@ -622,7 +622,7 @@ React.createElement(() => {
622
622
  React UI docs. You may not need it in your application.
623
623
  */}
624
624
  return (
625
- <RUIProvider globalProps={{
625
+ <GlobalPropsProvider globalProps={{
626
626
  Modal: { preventScrollUnderneath: window.document.documentElement }
627
627
  }}>
628
628
  <Button
@@ -665,7 +665,7 @@ React.createElement(() => {
665
665
  </Modal>
666
666
  )}
667
667
  </div>
668
- </RUIProvider>
668
+ </GlobalPropsProvider>
669
669
  );
670
670
  });
671
671
  ```
@@ -690,7 +690,7 @@ React.createElement(() => {
690
690
  React UI docs. You may not need it in your application.
691
691
  */}
692
692
  return (
693
- <RUIProvider globalProps={{
693
+ <GlobalPropsProvider globalProps={{
694
694
  Modal: { preventScrollUnderneath: window.document.documentElement }
695
695
  }}>
696
696
  <Button
@@ -734,7 +734,7 @@ React.createElement(() => {
734
734
  </Modal>
735
735
  )}
736
736
  </div>
737
- </RUIProvider>
737
+ </GlobalPropsProvider>
738
738
  );
739
739
  });
740
740
  ```
@@ -754,7 +754,7 @@ React.createElement(() => {
754
754
  React UI docs. You may not need it in your application.
755
755
  */}
756
756
  return (
757
- <RUIProvider globalProps={{
757
+ <GlobalPropsProvider globalProps={{
758
758
  Modal: { preventScrollUnderneath: window.document.documentElement }
759
759
  }}>
760
760
  <Button
@@ -807,7 +807,7 @@ React.createElement(() => {
807
807
  </Modal>
808
808
  )}
809
809
  </div>
810
- </RUIProvider>
810
+ </GlobalPropsProvider>
811
811
  );
812
812
  });
813
813
  ```
@@ -936,7 +936,7 @@ React.createElement(() => {
936
936
  React UI docs. You may not need it in your application.
937
937
  */}
938
938
  return (
939
- <RUIProvider globalProps={{
939
+ <GlobalPropsProvider globalProps={{
940
940
  Modal: { preventScrollUnderneath: window.document.documentElement }
941
941
  }}>
942
942
  <Button
@@ -999,7 +999,7 @@ React.createElement(() => {
999
999
  </Modal>
1000
1000
  )}
1001
1001
  </div>
1002
- </RUIProvider>
1002
+ </GlobalPropsProvider>
1003
1003
  );
1004
1004
  });
1005
1005
  ```
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../utils/classNames';
5
5
  import { transferProps } from '../../utils/transferProps';
6
6
  import styles from './Paper.module.scss';
@@ -1,9 +1,10 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { withGlobalProps } from '../../provider';
4
+ import { withGlobalProps } from '../../providers/globalProps';
5
5
  import { classNames } from '../../utils/classNames';
6
6
  import { transferProps } from '../../utils/transferProps';
7
+ import cleanPlacementStyle from './_helpers/cleanPlacementStyle';
7
8
  import getRootSideClassName from './_helpers/getRootSideClassName';
8
9
  import getRootAlignmentClassName from './_helpers/getRootAlignmentClassName';
9
10
  import styles from './Popover.module.scss';
@@ -12,24 +13,42 @@ export const Popover = React.forwardRef((props, ref) => {
12
13
  const {
13
14
  placement,
14
15
  children,
16
+ placementStyle,
17
+ popoverTargetId,
15
18
  portalId,
16
19
  ...restProps
17
20
  } = props;
18
21
 
19
22
  const PopoverEl = (
20
- <div
21
- {...transferProps(restProps)}
22
- className={classNames(
23
- styles.root,
24
- ref && styles.isRootControlled,
25
- getRootSideClassName(placement, styles),
26
- getRootAlignmentClassName(placement, styles),
23
+ <>
24
+ {/**
25
+ * This hack is needed because the default behavior of the Popover API is to place the popover into a
26
+ * top-layer. It is currently not possible to position an element in the top-layer relative to a normal element.
27
+ * This will create a hidden browser popover, then with CSS it will open and close the RUI popover.
28
+ */}
29
+ {!!popoverTargetId && (
30
+ <div
31
+ className={styles.helper}
32
+ id={popoverTargetId}
33
+ popover="auto"
34
+ />
27
35
  )}
28
- ref={ref}
29
- >
30
- {children}
31
- <span className={styles.arrow} />
32
- </div>
36
+ <div
37
+ {...transferProps(restProps)}
38
+ className={classNames(
39
+ styles.root,
40
+ ref && styles.isRootControlled,
41
+ popoverTargetId && styles.controlledPopover,
42
+ getRootSideClassName(placement, styles),
43
+ getRootAlignmentClassName(placement, styles),
44
+ )}
45
+ ref={ref}
46
+ style={placementStyle ? cleanPlacementStyle(placementStyle) : null}
47
+ >
48
+ {children}
49
+ <span className={styles.arrow} />
50
+ </div>
51
+ </>
33
52
  );
34
53
 
35
54
  if (portalId === null) {
@@ -41,6 +60,8 @@ export const Popover = React.forwardRef((props, ref) => {
41
60
 
42
61
  Popover.defaultProps = {
43
62
  placement: 'bottom',
63
+ placementStyle: null,
64
+ popoverTargetId: null,
44
65
  portalId: null,
45
66
  };
46
67
 
@@ -67,6 +88,30 @@ Popover.propTypes = {
67
88
  'left-start',
68
89
  'left-end',
69
90
  ]),
91
+ /**
92
+ * Used for positioning the popover with a library like Floating UI. It is filtered,
93
+ * then passed to the popover as the `style` prop.
94
+ */
95
+ placementStyle: PropTypes.shape({
96
+ bottom: PropTypes.string,
97
+ inset: PropTypes.string,
98
+ 'inset-block-end': PropTypes.string,
99
+ 'inset-block-start': PropTypes.string,
100
+ 'inset-inline-end': PropTypes.string,
101
+ 'inset-inline-start': PropTypes.string,
102
+ left: PropTypes.string,
103
+ position: PropTypes.string,
104
+ right: PropTypes.string,
105
+ top: PropTypes.string,
106
+ 'transform-origin': PropTypes.string,
107
+ translate: PropTypes.string,
108
+ }),
109
+ /**
110
+ * If set, the popover will become controlled, meaning it will be hidden by default and will need a trigger to open.
111
+ * This sets the ID of the internal helper element for the popover.
112
+ * Assign the same ID to `popovertarget` of a trigger to make it open and close.
113
+ */
114
+ popoverTargetId: PropTypes.string,
70
115
  /**
71
116
  * If set, popover is rendered in the React Portal with that ID.
72
117
  */