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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. package/.nvmrc +1 -1
  2. package/dist/react-ui.css +14 -14
  3. package/dist/react-ui.development.css +225 -14
  4. package/dist/react-ui.development.js +102 -62
  5. package/dist/react-ui.js +1 -1
  6. package/package.json +12 -1
  7. package/src/components/Alert/Alert.jsx +3 -5
  8. package/src/components/Alert/Alert.module.scss +3 -3
  9. package/src/components/Alert/README.md +22 -10
  10. package/src/components/Badge/Badge.jsx +1 -1
  11. package/src/components/Button/Button.jsx +1 -1
  12. package/src/components/ButtonGroup/ButtonGroup.jsx +1 -1
  13. package/src/components/Card/Card.jsx +1 -1
  14. package/src/components/Card/Card.module.scss +6 -5
  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 +22 -0
  18. package/src/components/CheckboxField/CheckboxField.jsx +9 -3
  19. package/src/components/CheckboxField/README.md +110 -5
  20. package/src/components/FileInputField/FileInputField.jsx +1 -1
  21. package/src/components/FormLayout/FormLayout.jsx +1 -1
  22. package/src/components/FormLayout/FormLayoutCustomField.jsx +1 -1
  23. package/src/components/Grid/Grid.jsx +1 -1
  24. package/src/components/Grid/GridSpan.jsx +1 -1
  25. package/src/components/InputGroup/InputGroup.jsx +2 -2
  26. package/src/components/InputGroup/InputGroup.module.scss +9 -5
  27. package/src/components/Modal/Modal.jsx +1 -1
  28. package/src/components/Modal/ModalBody.jsx +1 -1
  29. package/src/components/Modal/ModalCloseButton.jsx +3 -5
  30. package/src/components/Modal/ModalContent.jsx +1 -1
  31. package/src/components/Modal/ModalFooter.jsx +1 -1
  32. package/src/components/Modal/ModalHeader.jsx +1 -1
  33. package/src/components/Modal/ModalTitle.jsx +1 -1
  34. package/src/components/Modal/README.md +18 -18
  35. package/src/components/Paper/Paper.jsx +1 -1
  36. package/src/components/Popover/Popover.jsx +58 -13
  37. package/src/components/Popover/Popover.module.scss +37 -9
  38. package/src/components/Popover/PopoverWrapper.jsx +1 -1
  39. package/src/components/Popover/README.md +60 -3
  40. package/src/components/Popover/_helpers/cleanPlacementStyle.js +20 -0
  41. package/src/components/Radio/README.md +103 -0
  42. package/src/components/Radio/Radio.jsx +9 -3
  43. package/src/components/Radio/Radio.module.scss +4 -0
  44. package/src/components/ScrollView/ScrollView.jsx +3 -5
  45. package/src/components/SelectField/README.md +103 -0
  46. package/src/components/SelectField/SelectField.jsx +9 -3
  47. package/src/components/Table/Table.jsx +1 -1
  48. package/src/components/Tabs/Tabs.jsx +1 -1
  49. package/src/components/Tabs/TabsItem.jsx +1 -1
  50. package/src/components/Text/Text.jsx +1 -1
  51. package/src/components/TextArea/TextArea.jsx +1 -1
  52. package/src/components/TextField/README.md +14 -2
  53. package/src/components/TextField/TextField.jsx +1 -1
  54. package/src/components/TextLink/README.md +10 -3
  55. package/src/components/TextLink/TextLink.jsx +1 -1
  56. package/src/components/TextLink/_theme.scss +3 -3
  57. package/src/components/Toggle/README.md +83 -1
  58. package/src/components/Toggle/Toggle.jsx +9 -3
  59. package/src/components/Toolbar/Toolbar.jsx +1 -1
  60. package/src/components/Toolbar/ToolbarGroup.jsx +1 -1
  61. package/src/components/Toolbar/ToolbarItem.jsx +1 -1
  62. package/src/components/_helpers/resolveContextOrProp.js +6 -3
  63. package/src/index.js +3 -2
  64. package/src/providers/globalProps/GlobalPropsContext.jsx +5 -0
  65. package/src/providers/globalProps/GlobalPropsProvider.jsx +33 -0
  66. package/src/providers/globalProps/index.js +3 -0
  67. package/src/{provider → providers/globalProps}/withGlobalProps.jsx +16 -16
  68. package/src/providers/translations/TranslationsContext.jsx +6 -0
  69. package/src/providers/translations/TranslationsProvider.jsx +33 -0
  70. package/src/providers/translations/index.js +2 -0
  71. package/src/styles/elements/_links.scss +7 -2
  72. package/src/styles/theme/_form-fields.scss +19 -0
  73. package/src/styles/theme/_links.scss +4 -3
  74. package/src/styles/tools/_collections.scss +79 -5
  75. package/src/styles/tools/form-fields/_foundation.scss +6 -4
  76. package/src/styles/tools/form-fields/_variants.scss +5 -1
  77. package/src/theme.scss +2 -1
  78. package/src/provider/RUIContext.jsx +0 -9
  79. package/src/provider/RUIProvider.jsx +0 -42
  80. package/src/provider/index.js +0 -3
@@ -52,6 +52,10 @@
52
52
  @include foundation.label-required();
53
53
  }
54
54
 
55
+ .isRootRequired .optionLabel {
56
+ @include foundation.label-required($show-require-sign: false);
57
+ }
58
+
55
59
  // States
56
60
  .isRootStateInvalid {
57
61
  @include variants.validation(invalid);
@@ -6,10 +6,8 @@ import React, {
6
6
  useRef,
7
7
  useState,
8
8
  } from 'react';
9
- import {
10
- RUIContext,
11
- withGlobalProps,
12
- } from '../../provider';
9
+ import { TranslationsContext } from '../../providers/translations';
10
+ import { withGlobalProps } from '../../providers/globalProps';
13
11
  import { classNames } from '../../utils/classNames';
14
12
  import { transferProps } from '../../utils/transferProps';
15
13
  import { getElementsPositionDifference } from './_helpers/getElementsPositionDifference';
@@ -48,7 +46,7 @@ export const ScrollView = React.forwardRef((props, ref) => {
48
46
  ...restProps
49
47
  } = props;
50
48
 
51
- const { translations } = useContext(RUIContext);
49
+ const translations = useContext(TranslationsContext);
52
50
 
53
51
  const [isAutoScrollInProgress, setIsAutoScrollInProgress] = useState(false);
54
52
  const [isScrolledAtStart, setIsScrolledAtStart] = useState(false);
@@ -592,6 +592,109 @@ React.createElement(() => {
592
592
  })
593
593
  ```
594
594
 
595
+ ### Required State
596
+
597
+ The required state indicates that the input is mandatory.
598
+
599
+ ```docoff-react-preview
600
+ React.createElement(() => {
601
+ const [fruit, setFruit] = React.useState('apple');
602
+ return (
603
+ <SelectField
604
+ label="Your favourite fruit"
605
+ onChange={(e) => setFruit(e.target.value)}
606
+ options={[
607
+ {
608
+ label: 'Apple',
609
+ value: 'apple',
610
+ },
611
+ {
612
+ label: 'Banana',
613
+ value: 'banana',
614
+ },
615
+ {
616
+ label: 'Grapefruit',
617
+ value: 'grapefruit',
618
+ },
619
+ ]}
620
+ value={fruit}
621
+ required
622
+ />
623
+ );
624
+ });
625
+ ```
626
+
627
+ #### Styling the Required State
628
+
629
+ All form fields in React UI can be
630
+ [styled](/docs/customize/theming/forms/#required-state)
631
+ to indicate the required state.
632
+
633
+ However, you may find yourself in a situation where a form field is valid in
634
+ both selected and unselected states, for example to turn on or off a feature.
635
+ If your project uses the label color as the primary means to indicate the
636
+ required state of input fields and the usual asterisk `*` is omitted, you may
637
+ want to keep the label color consistent for both states to avoid confusion.
638
+
639
+ For this edge case, there is the `renderAsRequired` prop:
640
+
641
+ ```docoff-react-preview
642
+ React.createElement(() => {
643
+ const [fruit, setFruit] = React.useState('apple');
644
+ const options = [
645
+ {
646
+ label: 'Apple',
647
+ value: 'apple',
648
+ },
649
+ {
650
+ label: 'Banana',
651
+ value: 'banana',
652
+ },
653
+ {
654
+ label: 'Grapefruit',
655
+ value: 'grapefruit',
656
+ },
657
+ ];
658
+ return (
659
+ <React.Fragment>
660
+ <style>
661
+ {`
662
+ .example {
663
+ display: flex;
664
+ flex-wrap: wrap;
665
+ gap: 1rem 0.5rem;
666
+ }
667
+
668
+ .example--themed-form-fields {
669
+ --rui-FormField__label__color: var(--rui-color-text-secondary);
670
+ --rui-FormField--required__label__color: var(--rui-color-text-primary);
671
+ --rui-FormField--required__sign: '';
672
+ }
673
+ `}
674
+ </style>
675
+ <div class="example example--themed-form-fields">
676
+ <SelectField
677
+ label="This field is optional"
678
+ onChange={(e) => setFruit(e.target.value)}
679
+ options={options}
680
+ value={fruit}
681
+ />
682
+ <SelectField
683
+ label="This field is optional but looks like required"
684
+ onChange={(e) => setFruit(e.target.value)}
685
+ options={options}
686
+ value={fruit}
687
+ renderAsRequired
688
+ />
689
+ </div>
690
+ </React.Fragment>
691
+ );
692
+ });
693
+ ```
694
+
695
+ It renders the field as if it was required, but doesn't add the `required`
696
+ attribute to the actual input.
697
+
595
698
  ### Disabled State
596
699
 
597
700
  It's possible to disable just some options or the whole input.
@@ -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';
@@ -21,6 +21,7 @@ export const SelectField = React.forwardRef((props, ref) => {
21
21
  label,
22
22
  layout,
23
23
  options,
24
+ renderAsRequired,
24
25
  required,
25
26
  size,
26
27
  validationState,
@@ -43,7 +44,7 @@ export const SelectField = React.forwardRef((props, ref) => {
43
44
  ? styles.isRootLayoutHorizontal
44
45
  : styles.isRootLayoutVertical,
45
46
  inputGroupContext && styles.isRootGrouped,
46
- required && styles.isRootRequired,
47
+ (renderAsRequired || required) && styles.isRootRequired,
47
48
  getRootSizeClassName(
48
49
  resolveContextOrProp(inputGroupContext && inputGroupContext.size, size),
49
50
  styles,
@@ -136,6 +137,7 @@ SelectField.defaultProps = {
136
137
  id: undefined,
137
138
  isLabelVisible: true,
138
139
  layout: 'vertical',
140
+ renderAsRequired: false,
139
141
  required: false,
140
142
  size: 'medium',
141
143
  validationState: null,
@@ -227,7 +229,11 @@ SelectField.propTypes = {
227
229
  })),
228
230
  ]).isRequired,
229
231
  /**
230
- * If `true`, the input will be required.
232
+ * If `true`, the input will be rendered as if it was required.
233
+ */
234
+ renderAsRequired: PropTypes.bool,
235
+ /**
236
+ * If `true`, the input will be made and rendered as required, regardless of the `renderAsRequired` prop.
231
237
  */
232
238
  required: PropTypes.bool,
233
239
  /**
@@ -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 { TableHeaderCell } from './_components/TableHeaderCell';
6
6
  import { TableBodyCell } from './_components/TableBodyCell';
@@ -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 './Tabs.module.scss';
6
6
 
@@ -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 './TabsItem.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 { 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';
@@ -388,7 +388,13 @@ have.
388
388
  label="User name"
389
389
  onChange={() => {}}
390
390
  validationState="warning"
391
- validationText="Account with this name already exists, pick a different one."
391
+ validationText={(
392
+ <>
393
+ Account with this name already exists, pick a different one.
394
+ {' '}
395
+ <TextLink href="#" label="Forgot your password?" />
396
+ </>
397
+ )}
392
398
  value="joe"
393
399
  required
394
400
  />
@@ -411,7 +417,13 @@ have.
411
417
  label="User name"
412
418
  onChange={() => {}}
413
419
  validationState="warning"
414
- validationText="Account with this name already exists, pick a different one."
420
+ validationText={(
421
+ <>
422
+ Account with this name already exists, pick a different one.
423
+ {' '}
424
+ <TextLink href="#" label="Forgot your password?" />
425
+ </>
426
+ )}
415
427
  variant="filled"
416
428
  value="joe"
417
429
  required
@@ -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';
@@ -64,13 +64,20 @@ helps to improve its accessibility.
64
64
 
65
65
  ## Theming
66
66
 
67
+ ℹ️ The TextLink component is context-aware and can inherit text color from its
68
+ parent component. This applies for components using
69
+ [Feedback color collection](/docs/foundation/collections#colors) and for
70
+ components in any of the supported
71
+ [validation states](/docs/foundation/colors#validation-states).
72
+ In such cases, the custom properties marked with an asterisk (\*) are ignored.
73
+
67
74
  | Custom Property | Description |
68
75
  |-------------------------------------------|-------------------------------------|
69
- | `--rui-TextLink__color` | Text color |
76
+ | `--rui-TextLink__color` \* | Text color |
70
77
  | `--rui-TextLink__text-decoration` | Text decoration, e.g. underline |
71
- | `--rui-TextLink--hover__color` | Text color on hover |
78
+ | `--rui-TextLink--hover__color` \* | Text color on hover |
72
79
  | `--rui-TextLink--hover__text-decoration` | Text decoration on hover |
73
- | `--rui-TextLink--active__color` | Text color in the active state |
80
+ | `--rui-TextLink--active__color` \* | Text color in the active state |
74
81
  | `--rui-TextLink--active__text-decoration` | Text decoration in the active state |
75
82
 
76
83
  [a-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes
@@ -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 './TextLink.module.scss';
6
6
 
@@ -1,6 +1,6 @@
1
- $color: var(--rui-TextLink__color);
1
+ $color: var(--rui-local-link-color, var(--rui-TextLink__color));
2
2
  $text-decoration: var(--rui-TextLink__text-decoration);
3
- $hover-color: var(--rui-TextLink--hover__color);
3
+ $hover-color: var(--rui-local-link-color-hover, var(--rui-TextLink--hover__color));
4
4
  $hover-text-decoration: var(--rui-TextLink--hover__text-decoration);
5
- $active-color: var(--rui-TextLink--active__color);
5
+ $active-color: var(--rui-local-link-color-active, var(--rui-TextLink--active__color));
6
6
  $active-text-decoration: var(--rui-TextLink--active__text-decoration);
@@ -148,13 +148,95 @@ React.createElement(() => {
148
148
  label="Listen in studio quality"
149
149
  onChange={() => setStudioQuality(!studioQuality)}
150
150
  validationState="invalid"
151
- validationText="Please upgrade your plan to make this option available."
151
+ validationText={(
152
+ <>
153
+ Please
154
+ {' '}
155
+ <TextLink href="#" label="upgrade your plan" />
156
+ {' '}
157
+ to make this option available.
158
+ </>
159
+ )}
152
160
  />
153
161
  </>
154
162
  );
155
163
  });
156
164
  ```
157
165
 
166
+ ### Required State
167
+
168
+ The required state indicates that the input is mandatory.
169
+
170
+ ```docoff-react-preview
171
+ React.createElement(() => {
172
+ const [studioQuality, setStudioQuality] = React.useState(true);
173
+ return (
174
+ <Toggle
175
+ checked={studioQuality}
176
+ label="Listen in studio quality"
177
+ onChange={() => setStudioQuality(!studioQuality)}
178
+ required
179
+ />
180
+ );
181
+ });
182
+ ```
183
+
184
+ #### Styling the Required State
185
+
186
+ All form fields in React UI can be
187
+ [styled](/docs/customize/theming/forms/#required-state)
188
+ to indicate the required state.
189
+
190
+ However, you may find yourself in a situation where a form field is valid in
191
+ both checked and unchecked states, for example to turn on or off a feature.
192
+ If your project uses the label color as the primary means to indicate the
193
+ required state of input fields and the usual asterisk `*` is omitted, you may
194
+ want to keep the label color consistent for both states to avoid confusion.
195
+
196
+ For this edge case, there is the `renderAsRequired` prop:
197
+
198
+ ```docoff-react-preview
199
+ React.createElement(() => {
200
+ const [optional, setOptional] = React.useState(false);
201
+ const [renderAsRequired, setRenderAsRequired] = React.useState(false);
202
+ return (
203
+ <React.Fragment>
204
+ <style>
205
+ {`
206
+ .example {
207
+ display: flex;
208
+ flex-wrap: wrap;
209
+ gap: 1rem 0.5rem;
210
+ }
211
+
212
+ .example--themed-form-fields {
213
+ --rui-FormField__label__color: var(--rui-color-text-secondary);
214
+ --rui-FormField--required__label__color: var(--rui-color-text-primary);
215
+ --rui-FormField--required__sign: '';
216
+ }
217
+ `}
218
+ </style>
219
+ <div class="example example--themed-form-fields">
220
+ <Toggle
221
+ checked={optional}
222
+ label="This field is optional"
223
+ onChange={() => setOptional(!optional)}
224
+ />
225
+ <Toggle
226
+ checked={renderAsRequired}
227
+ label="This field is optional but looks like required"
228
+ onChange={() => setRenderAsRequired(!renderAsRequired)}
229
+ renderAsRequired
230
+ />
231
+ </div>
232
+ </React.Fragment>
233
+ );
234
+ });
235
+ ```
236
+
237
+ It renders the field as if it was required, but doesn't add the `required`
238
+ attribute to the actual input.
239
+
158
240
  ### Disabled State
159
241
 
160
242
  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';
@@ -15,6 +15,7 @@ export const Toggle = React.forwardRef((props, ref) => {
15
15
  isLabelVisible,
16
16
  label,
17
17
  labelPosition,
18
+ renderAsRequired,
18
19
  required,
19
20
  validationState,
20
21
  validationText,
@@ -31,7 +32,7 @@ export const Toggle = React.forwardRef((props, ref) => {
31
32
  context && context.layout === 'horizontal' ? styles.isRootLayoutHorizontal : styles.isRootLayoutVertical,
32
33
  labelPosition === 'before' && styles.hasRootLabelBefore,
33
34
  disabled && styles.isRootDisabled,
34
- required && styles.isRootRequired,
35
+ (required || renderAsRequired) && styles.isRootRequired,
35
36
  getRootValidationStateClassName(validationState, styles),
36
37
  )}
37
38
  htmlFor={id}
@@ -84,6 +85,7 @@ Toggle.defaultProps = {
84
85
  id: undefined,
85
86
  isLabelVisible: true,
86
87
  labelPosition: 'after',
88
+ renderAsRequired: false,
87
89
  required: false,
88
90
  validationState: null,
89
91
  validationText: null,
@@ -120,7 +122,11 @@ Toggle.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
  /**
@@ -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,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';
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { classNames } from '../../utils/classNames';
4
4
  import { transferProps } from '../../utils/transferProps';
5
- import { withGlobalProps } from '../../provider';
5
+ import { withGlobalProps } from '../../providers/globalProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
7
7
  import styles from './Toolbar.module.scss';
8
8
 
@@ -1,7 +1,10 @@
1
1
  export const resolveContextOrProp = (contextValue, propValue) => {
2
- if (contextValue != null) {
3
- return contextValue;
2
+ // We need to test:
3
+ // * `false` - for when the `contextValue` is boolean
4
+ // * `null` - for when the `contextValue` is non-boolean
5
+ if (contextValue === false || contextValue === null) {
6
+ return propValue;
4
7
  }
5
8
 
6
- return propValue;
9
+ return contextValue;
7
10
  };
package/src/index.js CHANGED
@@ -57,8 +57,9 @@ export {
57
57
  ToolbarItem,
58
58
  } from './components/Toolbar';
59
59
 
60
- // Provider
61
- export { RUIProvider } from './provider';
60
+ // Providers
61
+ export { GlobalPropsProvider } from './providers/globalProps';
62
+ export { TranslationsProvider } from './providers/translations';
62
63
 
63
64
  // Utils
64
65
  export { classNames } from './utils/classNames';
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ const GlobalPropsContext = React.createContext({});
4
+
5
+ export default GlobalPropsContext;
@@ -0,0 +1,33 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import { mergeDeep } from '../../utils/mergeDeep';
6
+ import GlobalPropsContext from './GlobalPropsContext';
7
+
8
+ const GlobalPropsProvider = ({
9
+ children,
10
+ globalProps,
11
+ }) => {
12
+ const contextGlobalProps = useContext(GlobalPropsContext);
13
+
14
+ return (
15
+ <GlobalPropsContext.Provider
16
+ value={mergeDeep(contextGlobalProps, globalProps)}
17
+ >
18
+ {children}
19
+ </GlobalPropsContext.Provider>
20
+ );
21
+ };
22
+
23
+ GlobalPropsProvider.defaultProps = {
24
+ children: null,
25
+ globalProps: {},
26
+ };
27
+
28
+ GlobalPropsProvider.propTypes = {
29
+ children: PropTypes.node,
30
+ globalProps: PropTypes.shape({}),
31
+ };
32
+
33
+ export default GlobalPropsProvider;
@@ -0,0 +1,3 @@
1
+ export { default as GlobalPropsContext } from './GlobalPropsContext';
2
+ export { default as GlobalPropsProvider } from './GlobalPropsProvider';
3
+ export { default as withGlobalProps } from './withGlobalProps';
@@ -1,26 +1,24 @@
1
1
  import PropTypes from 'prop-types';
2
- import React from 'react';
3
- import RUIContext from './RUIContext';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import GlobalPropsContext from './GlobalPropsContext';
4
6
 
5
7
  export default (Component, componentName) => {
6
8
  const WithGlobalPropsComponent = ({
7
9
  forwardedRef,
8
10
  ...rest
9
- }) => (
10
- <RUIContext.Consumer>
11
- {({ globalProps }) => {
12
- const contextGlobalProps = globalProps ? globalProps[componentName] : null;
11
+ }) => {
12
+ const contextGlobalProps = useContext(GlobalPropsContext);
13
13
 
14
- return (
15
- <Component
16
- {...contextGlobalProps}
17
- {...rest}
18
- ref={forwardedRef}
19
- />
20
- );
21
- }}
22
- </RUIContext.Consumer>
23
- );
14
+ return (
15
+ <Component
16
+ {...contextGlobalProps[componentName] || {}}
17
+ {...rest}
18
+ ref={forwardedRef}
19
+ />
20
+ );
21
+ };
24
22
 
25
23
  WithGlobalPropsComponent.defaultProps = {
26
24
  forwardedRef: undefined,
@@ -29,6 +27,8 @@ export default (Component, componentName) => {
29
27
  WithGlobalPropsComponent.propTypes = {
30
28
  forwardedRef: PropTypes.oneOfType([
31
29
  PropTypes.func,
30
+
31
+ // The props can be of any type and here we need to support them all
32
32
  // eslint-disable-next-line react/forbid-prop-types
33
33
  PropTypes.shape({ current: PropTypes.any }),
34
34
  ]),
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import defaultTranslations from '../../translations/en';
3
+
4
+ const RUIContext = React.createContext(defaultTranslations);
5
+
6
+ export default RUIContext;
@@ -0,0 +1,33 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import { mergeDeep } from '../../utils/mergeDeep';
6
+ import TranslationsContext from './TranslationsContext';
7
+
8
+ const TranslationsProvider = ({
9
+ children,
10
+ translations,
11
+ }) => {
12
+ const contextTranslations = useContext(TranslationsContext);
13
+
14
+ return (
15
+ <TranslationsContext.Provider
16
+ value={mergeDeep(contextTranslations, translations)}
17
+ >
18
+ {children}
19
+ </TranslationsContext.Provider>
20
+ );
21
+ };
22
+
23
+ TranslationsProvider.defaultProps = {
24
+ children: null,
25
+ translations: {},
26
+ };
27
+
28
+ TranslationsProvider.propTypes = {
29
+ children: PropTypes.node,
30
+ translations: PropTypes.shape({}),
31
+ };
32
+
33
+ export default TranslationsProvider;
@@ -0,0 +1,2 @@
1
+ export { default as TranslationsContext } from './TranslationsContext';
2
+ export { default as TranslationsProvider } from './TranslationsProvider';