@react-ui-org/react-ui 0.59.3 → 0.60.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.
- package/dist/react-ui.css +3 -3
- package/dist/react-ui.development.css +6 -0
- package/dist/react-ui.development.js +41 -31
- package/dist/react-ui.js +1 -1
- package/package.json +1 -1
- package/src/components/ButtonGroup/ButtonGroup.jsx +1 -1
- package/src/components/Card/Card.module.scss +1 -0
- package/src/components/Card/CardFooter.jsx +1 -1
- package/src/components/Card/README.md +2 -0
- package/src/components/Card/_theme.scss +2 -0
- package/src/components/FileInputField/FileInputField.jsx +8 -3
- package/src/components/FileInputField/FileInputField.module.scss +4 -0
- package/src/components/FormLayout/FormLayout.jsx +1 -1
- package/src/components/FormLayout/FormLayoutCustomField.jsx +1 -1
- package/src/components/Grid/Grid.jsx +1 -1
- package/src/components/Grid/GridSpan.jsx +1 -1
- package/src/components/InputGroup/InputGroup.jsx +1 -1
- package/src/components/Modal/Modal.jsx +14 -1
- package/src/components/Modal/ModalBody.jsx +1 -1
- package/src/components/Modal/ModalContent.jsx +1 -1
- package/src/components/Modal/_helpers/dialogOnClickHandler.js +6 -0
- package/src/components/ScrollView/ScrollView.jsx +39 -9
- package/src/components/ScrollView/_hooks/useScrollPositionHook.js +4 -4
- package/src/components/Text/Text.jsx +1 -1
- package/src/components/Toolbar/Toolbar.jsx +1 -1
- package/src/components/Toolbar/ToolbarGroup.jsx +1 -1
- package/src/components/Toolbar/ToolbarItem.jsx +1 -1
- package/src/helpers/isChildrenEmpty/README.md +57 -0
- package/src/helpers/isChildrenEmpty/index.js +1 -0
- package/src/index.js +1 -0
- package/src/theme.scss +2 -0
- package/src/translations/en.js +1 -0
- /package/src/{components/_helpers → helpers/isChildrenEmpty}/isChildrenEmpty.js +0 -0
package/package.json
CHANGED
@@ -6,7 +6,7 @@ import { withGlobalProps } from '../../providers/globalProps';
|
|
6
6
|
import { classNames } from '../../helpers/classNames/classNames';
|
7
7
|
import { transferProps } from '../../helpers/transferProps';
|
8
8
|
import { getRootPriorityClassName } from '../_helpers/getRootPriorityClassName';
|
9
|
-
import { isChildrenEmpty } from '
|
9
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
10
10
|
import styles from './ButtonGroup.module.scss';
|
11
11
|
import { ButtonGroupContext } from './ButtonGroupContext';
|
12
12
|
|
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { transferProps } from '../../helpers/transferProps';
|
4
4
|
import { withGlobalProps } from '../../providers/globalProps';
|
5
|
-
import { isChildrenEmpty } from '
|
5
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
6
6
|
import styles from './Card.module.scss';
|
7
7
|
|
8
8
|
export const CardFooter = ({
|
@@ -300,6 +300,8 @@ Separate your card actions with CardFooter. See
|
|
300
300
|
| `--rui-Card--raised__box-shadow` | Box shadow of raised card |
|
301
301
|
| `--rui-Card--disabled__background-color` | Card background color in disabled state |
|
302
302
|
| `--rui-Card--disabled__opacity` | Card opacity in disabled state |
|
303
|
+
| `--rui-Card--disabled__border-width` | Card border width in disabled state |
|
304
|
+
| `--rui-Card--disabled__border-color` | Card border color in disabled state |
|
303
305
|
|
304
306
|
### Theming Variants
|
305
307
|
|
@@ -9,3 +9,5 @@ $raised-box-shadow: var(--rui-Card--raised__box-shadow);
|
|
9
9
|
|
10
10
|
$disabled-background-color: var(--rui-Card--disabled__background-color);
|
11
11
|
$disabled-opacity: var(--rui-Card--disabled__opacity);
|
12
|
+
$disabled-border-width: var(--rui-Card--disabled__border-width);
|
13
|
+
$disabled-border-color: var(--rui-Card--disabled__border-color);
|
@@ -198,15 +198,20 @@ export const FileInputField = React.forwardRef((props, ref) => {
|
|
198
198
|
type="button"
|
199
199
|
>
|
200
200
|
<Text lines={1}>
|
201
|
-
{
|
201
|
+
{isDragging && (
|
202
|
+
<span className={styles.dropFileHereText}>
|
203
|
+
{translations.FileInputField.dropFileHere}
|
204
|
+
</span>
|
205
|
+
)}
|
206
|
+
{!isDragging && !selectedFileNames.length && (
|
202
207
|
<>
|
203
208
|
<span className={styles.dropZoneLink}>{translations.FileInputField.browse}</span>
|
204
209
|
{' '}
|
205
210
|
{translations.FileInputField.drop}
|
206
211
|
</>
|
207
212
|
)}
|
208
|
-
{selectedFileNames.length === 1 && selectedFileNames[0]}
|
209
|
-
{selectedFileNames.length > 1 && (
|
213
|
+
{!isDragging && selectedFileNames.length === 1 && selectedFileNames[0]}
|
214
|
+
{!isDragging && selectedFileNames.length > 1 && (
|
210
215
|
<>
|
211
216
|
{selectedFileNames.length}
|
212
217
|
{' '}
|
@@ -3,7 +3,7 @@ import React, { useMemo } from 'react';
|
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { classNames } from '../../helpers/classNames/classNames';
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import { FormLayoutContext } from './FormLayoutContext';
|
8
8
|
import styles from './FormLayout.module.scss';
|
9
9
|
|
@@ -5,7 +5,7 @@ import { classNames } from '../../helpers/classNames/classNames';
|
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
6
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
7
7
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
8
|
-
import { isChildrenEmpty } from '
|
8
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
9
9
|
import { FormLayoutContext } from './FormLayoutContext';
|
10
10
|
import styles from './FormLayoutCustomField.module.scss';
|
11
11
|
|
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { transferProps } from '../../helpers/transferProps';
|
5
|
-
import { isChildrenEmpty } from '
|
5
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
6
6
|
import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
|
7
7
|
import styles from './Grid.module.scss';
|
8
8
|
|
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { transferProps } from '../../helpers/transferProps';
|
5
|
-
import { isChildrenEmpty } from '
|
5
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
6
6
|
import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
|
7
7
|
import styles from './Grid.module.scss';
|
8
8
|
|
@@ -8,7 +8,7 @@ import { classNames } from '../../helpers/classNames/classNames';
|
|
8
8
|
import { transferProps } from '../../helpers/transferProps';
|
9
9
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
10
10
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
11
|
-
import { isChildrenEmpty } from '
|
11
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
12
12
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
13
13
|
import { FormLayoutContext } from '../FormLayout';
|
14
14
|
import { Text } from '../Text';
|
@@ -61,6 +61,7 @@ export const Modal = ({
|
|
61
61
|
...restProps
|
62
62
|
}) => {
|
63
63
|
const internalDialogRef = useRef();
|
64
|
+
const mouseDownTarget = useRef(null);
|
64
65
|
|
65
66
|
useEffect(() => {
|
66
67
|
internalDialogRef.current.showModal();
|
@@ -79,7 +80,13 @@ export const Modal = ({
|
|
79
80
|
[closeButtonRef, restProps.onCancel],
|
80
81
|
);
|
81
82
|
const onClick = useCallback(
|
82
|
-
(e) => dialogOnClickHandler(
|
83
|
+
(e) => dialogOnClickHandler(
|
84
|
+
e,
|
85
|
+
closeButtonRef,
|
86
|
+
internalDialogRef,
|
87
|
+
allowCloseOnBackdropClick,
|
88
|
+
mouseDownTarget.current,
|
89
|
+
),
|
83
90
|
[allowCloseOnBackdropClick, closeButtonRef, internalDialogRef],
|
84
91
|
);
|
85
92
|
const onClose = useCallback(
|
@@ -101,11 +108,17 @@ export const Modal = ({
|
|
101
108
|
primaryButtonRef,
|
102
109
|
],
|
103
110
|
);
|
111
|
+
|
112
|
+
const onMouseDown = useCallback((e) => {
|
113
|
+
mouseDownTarget.current = e.target;
|
114
|
+
}, []);
|
115
|
+
|
104
116
|
const events = {
|
105
117
|
onCancel,
|
106
118
|
onClick,
|
107
119
|
onClose,
|
108
120
|
onKeyDown,
|
121
|
+
onMouseDown,
|
109
122
|
};
|
110
123
|
|
111
124
|
if (portalId === null) {
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { classNames } from '../../helpers/classNames/classNames';
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import { getScrollingClassName } from './_helpers/getScrollingClassName';
|
8
8
|
import styles from './ModalBody.module.scss';
|
9
9
|
|
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { transferProps } from '../../helpers/transferProps';
|
5
|
-
import { isChildrenEmpty } from '
|
5
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
6
6
|
import styles from './ModalContent.module.scss';
|
7
7
|
|
8
8
|
export const ModalContent = ({
|
@@ -17,12 +17,18 @@ export const dialogOnClickHandler = (
|
|
17
17
|
closeButtonRef,
|
18
18
|
dialogRef,
|
19
19
|
allowCloseOnBackdropClick,
|
20
|
+
mouseDownTarget,
|
20
21
|
) => {
|
21
22
|
// If it is not allowed to close modal on backdrop click, do nothing.
|
22
23
|
if (!allowCloseOnBackdropClick) {
|
23
24
|
return;
|
24
25
|
}
|
25
26
|
|
27
|
+
// If the click started on the inside of the dialog, do nothing.
|
28
|
+
if (e.target !== mouseDownTarget) {
|
29
|
+
return;
|
30
|
+
}
|
31
|
+
|
26
32
|
// Detection of the click on the backdrop is based on the following conditions:
|
27
33
|
// 1. The click target is the dialog itself. This prevents detection of clicks on the dialog's children.
|
28
34
|
// 2. The click is outside the dialog's boundaries.
|
@@ -5,6 +5,7 @@ import React, {
|
|
5
5
|
useLayoutEffect,
|
6
6
|
useRef,
|
7
7
|
useState,
|
8
|
+
useCallback,
|
8
9
|
} from 'react';
|
9
10
|
import { TranslationsContext } from '../../providers/translations';
|
10
11
|
import { withGlobalProps } from '../../providers/globalProps';
|
@@ -58,20 +59,26 @@ export const ScrollView = React.forwardRef((props, ref) => {
|
|
58
59
|
const blankRef = useRef(null);
|
59
60
|
const scrollViewViewportEl = ref ?? blankRef;
|
60
61
|
|
61
|
-
const handleScrollViewState = (currentPosition) => {
|
62
|
+
const handleScrollViewState = useCallback((currentPosition) => {
|
62
63
|
const isScrolledAtStartActive = currentPosition[scrollPositionStart]
|
63
64
|
<= -1 * EDGE_DETECTION_INACCURACY_PX;
|
64
65
|
const isScrolledAtEndActive = currentPosition[scrollPositionEnd]
|
65
66
|
>= EDGE_DETECTION_INACCURACY_PX;
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
setIsScrolledAtStart((prevIsScrolledAtStart) => {
|
69
|
+
if (isScrolledAtStartActive !== prevIsScrolledAtStart) {
|
70
|
+
return isScrolledAtStartActive;
|
71
|
+
}
|
72
|
+
return prevIsScrolledAtStart;
|
73
|
+
});
|
70
74
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
+
setIsScrolledAtEnd((prevIsScrolledAtEnd) => {
|
76
|
+
if (isScrolledAtEndActive !== prevIsScrolledAtEnd) {
|
77
|
+
return isScrolledAtEndActive;
|
78
|
+
}
|
79
|
+
return prevIsScrolledAtEnd;
|
80
|
+
});
|
81
|
+
}, [scrollPositionStart, scrollPositionEnd]);
|
75
82
|
|
76
83
|
/**
|
77
84
|
* It handles scroll event fired on `scrollViewViewportEl` element. If autoScroll is in progress,
|
@@ -146,7 +153,6 @@ export const ScrollView = React.forwardRef((props, ref) => {
|
|
146
153
|
|
147
154
|
useScrollPosition(
|
148
155
|
(currentPosition) => (handleScrollViewState(currentPosition)),
|
149
|
-
[isScrolledAtStart, isScrolledAtEnd],
|
150
156
|
scrollViewContentEl,
|
151
157
|
scrollViewViewportEl,
|
152
158
|
debounce,
|
@@ -163,6 +169,30 @@ export const ScrollView = React.forwardRef((props, ref) => {
|
|
163
169
|
[autoScroll, autoScrollChildrenKeys, autoScrollChildrenLength],
|
164
170
|
);
|
165
171
|
|
172
|
+
// ResizeObserver to detect when content or viewport dimensions change due to style changes
|
173
|
+
useLayoutEffect(() => {
|
174
|
+
const contentElement = scrollViewContentEl.current;
|
175
|
+
const viewportElement = scrollViewViewportEl.current;
|
176
|
+
|
177
|
+
if (!contentElement || !viewportElement) {
|
178
|
+
return () => {};
|
179
|
+
}
|
180
|
+
|
181
|
+
const resizeObserver = new ResizeObserver(() => {
|
182
|
+
handleScrollViewState(
|
183
|
+
getElementsPositionDifference(scrollViewContentEl, scrollViewViewportEl),
|
184
|
+
);
|
185
|
+
});
|
186
|
+
|
187
|
+
// Observe both content and viewport for dimension changes
|
188
|
+
resizeObserver.observe(contentElement);
|
189
|
+
resizeObserver.observe(viewportElement);
|
190
|
+
|
191
|
+
return () => {
|
192
|
+
resizeObserver.disconnect();
|
193
|
+
};
|
194
|
+
}, [scrollViewContentEl, scrollViewViewportEl, handleScrollViewState]);
|
195
|
+
|
166
196
|
const arrowHandler = (contentEl, viewportEl, scrollViewDirection, shiftDirection, step) => {
|
167
197
|
const offset = shiftDirection === 'next' ? step : -1 * step;
|
168
198
|
const differenceX = scrollViewDirection === 'horizontal' ? offset : 0;
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import {
|
2
|
-
useLayoutEffect,
|
3
2
|
useRef,
|
3
|
+
useEffect,
|
4
4
|
} from 'react';
|
5
5
|
import { getElementsPositionDifference } from '../_helpers/getElementsPositionDifference';
|
6
6
|
|
7
|
-
export const useScrollPosition = (effect,
|
7
|
+
export const useScrollPosition = (effect, contentEl, viewportEl, wait) => {
|
8
8
|
const throttleTimeout = useRef(null);
|
9
9
|
|
10
10
|
const callBack = (wasDelayed = false) => {
|
@@ -15,7 +15,7 @@ export const useScrollPosition = (effect, dependencies, contentEl, viewportEl, w
|
|
15
15
|
}
|
16
16
|
};
|
17
17
|
|
18
|
-
|
18
|
+
useEffect(() => {
|
19
19
|
const viewport = viewportEl.current;
|
20
20
|
|
21
21
|
const handleScroll = () => {
|
@@ -34,7 +34,7 @@ export const useScrollPosition = (effect, dependencies, contentEl, viewportEl, w
|
|
34
34
|
clearTimeout(throttleTimeout.current);
|
35
35
|
viewport.removeEventListener('scroll', handleScroll);
|
36
36
|
};
|
37
|
-
},
|
37
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
38
38
|
};
|
39
39
|
|
40
40
|
export default useScrollPosition;
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { classNames } from '../../helpers/classNames/classNames';
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import { getRootClampClassName } from './_helpers/getRootClampClassName';
|
8
8
|
import { getRootHyphensClassName } from './_helpers/getRootHyphensClassName';
|
9
9
|
import { getRootWordWrappingClassName } from './_helpers/getRootWordWrappingClassName';
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { classNames } from '../../helpers/classNames/classNames';
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import { getAlignClassName } from './_helpers/getAlignClassName';
|
8
8
|
import { getJustifyClassName } from './_helpers/getJustifyClassName';
|
9
9
|
import styles from './Toolbar.module.scss';
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
4
|
import { classNames } from '../../helpers/classNames/classNames';
|
5
5
|
import { transferProps } from '../../helpers/transferProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import { getAlignClassName } from './_helpers/getAlignClassName';
|
8
8
|
import styles from './Toolbar.module.scss';
|
9
9
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
3
3
|
import { classNames } from '../../helpers/classNames/classNames';
|
4
4
|
import { transferProps } from '../../helpers/transferProps';
|
5
5
|
import { withGlobalProps } from '../../providers/globalProps';
|
6
|
-
import { isChildrenEmpty } from '
|
6
|
+
import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
|
7
7
|
import styles from './Toolbar.module.scss';
|
8
8
|
|
9
9
|
export const ToolbarItem = ({
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# isChildrenEmpty
|
2
|
+
|
3
|
+
The `isChildrenEmpty` helper function determines whether the given children
|
4
|
+
value should be considered "empty".
|
5
|
+
|
6
|
+
It is useful in React when conditionally rendering components based on
|
7
|
+
whether children contain meaningful content.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
To use `isChildrenEmpty` helper, you need to import it first:
|
12
|
+
|
13
|
+
```js
|
14
|
+
import { isChildrenEmpty } from '@react-ui-org/react-ui';
|
15
|
+
```
|
16
|
+
|
17
|
+
Then use it:
|
18
|
+
|
19
|
+
```docoff-react-preview
|
20
|
+
|
21
|
+
React.createElement(() => {
|
22
|
+
const children = null;
|
23
|
+
const isEmpty = isChildrenEmpty(children);
|
24
|
+
|
25
|
+
if (isEmpty === false) {
|
26
|
+
return (
|
27
|
+
<div>{children}</div>
|
28
|
+
);
|
29
|
+
}
|
30
|
+
|
31
|
+
return (
|
32
|
+
<div>Children not provided</div>
|
33
|
+
);
|
34
|
+
});
|
35
|
+
```
|
36
|
+
|
37
|
+
```docoff-react-preview
|
38
|
+
React.createElement(() => {
|
39
|
+
const children = (
|
40
|
+
<>
|
41
|
+
<h1>Title</h1>
|
42
|
+
<p>Content</p>
|
43
|
+
</>
|
44
|
+
);
|
45
|
+
const isEmpty = isChildrenEmpty(children);
|
46
|
+
|
47
|
+
if (isEmpty === false) {
|
48
|
+
return (
|
49
|
+
<div>{children}</div>
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
return (
|
54
|
+
<div>Children not provided</div>
|
55
|
+
);
|
56
|
+
});
|
57
|
+
```
|
@@ -0,0 +1 @@
|
|
1
|
+
export { isChildrenEmpty } from './isChildrenEmpty';
|
package/src/index.js
CHANGED
package/src/theme.scss
CHANGED
@@ -832,6 +832,8 @@
|
|
832
832
|
--rui-Card--raised__box-shadow: var(--rui-shadow-layer-1);
|
833
833
|
--rui-Card--disabled__background-color: var(--rui-color-background-disabled);
|
834
834
|
--rui-Card--disabled__opacity: var(--rui-ratio-disabled-opacity);
|
835
|
+
--rui-Card--disabled__border-width: var(--rui-dimension-border-width-1);
|
836
|
+
--rui-Card--disabled__border-color: var(--rui-color-border-primary);
|
835
837
|
|
836
838
|
// Card: variant: success
|
837
839
|
--rui-Card--success__color: var(--rui-color-text-primary);
|
package/src/translations/en.js
CHANGED
File without changes
|