@onewelcome/react-lib-components 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Notifications/BaseModal/BaseModal.d.ts +1 -1
- package/dist/hooks/useGetDomRoot.d.ts +3 -0
- package/dist/react-lib-components.cjs.development.js +54 -18
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +55 -19
- package/dist/react-lib-components.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/ContextMenu/ContextMenu.tsx +18 -3
- package/src/Notifications/BaseModal/BaseModal.tsx +48 -41
- package/src/Notifications/Snackbar/SnackbarProvider/SnackbarProvider.tsx +7 -4
- package/src/Tooltip/Tooltip.tsx +9 -3
- package/src/hooks/useGetDomRoot.ts +40 -0
- package/src/hooks/usePosition.ts +2 -1
package/package.json
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
|
|
17
17
|
import React, {
|
|
18
18
|
ComponentPropsWithRef,
|
|
19
|
+
createRef,
|
|
19
20
|
ForwardRefRenderFunction,
|
|
20
21
|
ReactElement,
|
|
21
22
|
ReactNode,
|
|
23
|
+
RefObject,
|
|
22
24
|
useCallback,
|
|
23
25
|
useEffect,
|
|
24
26
|
useRef,
|
|
@@ -31,6 +33,7 @@ import { Placement, Offset } from "../hooks/usePosition";
|
|
|
31
33
|
import classes from "./ContextMenu.module.scss";
|
|
32
34
|
import { useBodyClick } from "../hooks/useBodyClick";
|
|
33
35
|
import { createPortal } from "react-dom";
|
|
36
|
+
import { useGetDomRoot } from "../hooks/useGetDomRoot";
|
|
34
37
|
|
|
35
38
|
export interface Props extends ComponentPropsWithRef<"div"> {
|
|
36
39
|
trigger: ReactElement<ButtonProps> | ReactElement<IconButtonProps>;
|
|
@@ -61,13 +64,14 @@ const ContextMenuComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
61
64
|
offset = { top: 0, bottom: 0, left: 0, right: 0 },
|
|
62
65
|
transformOrigin = { horizontal: "left", vertical: "top" },
|
|
63
66
|
debounceAmount,
|
|
64
|
-
domRoot
|
|
67
|
+
domRoot,
|
|
65
68
|
popoverProps,
|
|
66
69
|
...rest
|
|
67
70
|
}: Props,
|
|
68
71
|
ref
|
|
69
72
|
) => {
|
|
70
73
|
const anchorEl = useRef<HTMLButtonElement>(null);
|
|
74
|
+
const wrappingDivRef = (ref as RefObject<HTMLDivElement>) || createRef<HTMLDivElement>();
|
|
71
75
|
const [showContextMenu, setShowContextMenu] = useState(show);
|
|
72
76
|
const [hasBeenClosed, setHasBeenClosed] = useState(false);
|
|
73
77
|
const [selectedContextMenuItem, setSelectedContextMenuItem] = useState(-1);
|
|
@@ -78,6 +82,8 @@ const ContextMenuComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
78
82
|
); /** We need this, because whenever we use the arrow keys to select the contextmenu item, and we focus the currently selected item it fires the "click" listener in ContextMenuItem component. Instead, we only want this to fire if we press "enter" or "spacebar" so we set this to true whenever that is the case, and back to false when it has been executed. */
|
|
79
83
|
const [childrenCount] = useState(React.Children.count(children));
|
|
80
84
|
|
|
85
|
+
const { root } = useGetDomRoot(domRoot, wrappingDivRef);
|
|
86
|
+
|
|
81
87
|
if (!id) {
|
|
82
88
|
throw new Error("You need to provide an ID to the context menu");
|
|
83
89
|
}
|
|
@@ -198,8 +204,17 @@ const ContextMenuComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
198
204
|
setShowContextMenu(false);
|
|
199
205
|
}, []);
|
|
200
206
|
|
|
207
|
+
if (!root) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
201
211
|
return (
|
|
202
|
-
<div
|
|
212
|
+
<div
|
|
213
|
+
{...rest}
|
|
214
|
+
ref={wrappingDivRef}
|
|
215
|
+
onKeyDown={onArrowNavigation}
|
|
216
|
+
className={classes["context-menu"]}
|
|
217
|
+
>
|
|
203
218
|
{renderTrigger()}
|
|
204
219
|
{createPortal(
|
|
205
220
|
<Popover
|
|
@@ -224,7 +239,7 @@ const ContextMenuComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
224
239
|
{renderChildren()}
|
|
225
240
|
</ul>
|
|
226
241
|
</Popover>,
|
|
227
|
-
|
|
242
|
+
root
|
|
228
243
|
)}
|
|
229
244
|
</div>
|
|
230
245
|
);
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import React, { ForwardRefRenderFunction, ComponentPropsWithRef, useEffect } from "react";
|
|
17
|
+
import React, { ForwardRefRenderFunction, ComponentPropsWithRef, useEffect, useRef } from "react";
|
|
18
18
|
import { createPortal } from "react-dom";
|
|
19
|
+
import { useGetDomRoot } from "../../hooks/useGetDomRoot";
|
|
19
20
|
import classes from "./BaseModal.module.scss";
|
|
20
21
|
import { labelId, descriptionId } from "./BaseModalContext";
|
|
21
22
|
|
|
@@ -76,12 +77,14 @@ const BaseModalComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
76
77
|
disableBackdrop = false,
|
|
77
78
|
forceContainerOpen = false,
|
|
78
79
|
zIndex,
|
|
79
|
-
domRoot
|
|
80
|
+
domRoot,
|
|
80
81
|
...rest
|
|
81
82
|
}: Props,
|
|
82
83
|
ref
|
|
83
84
|
) => {
|
|
84
85
|
useSetBodyScroll(open);
|
|
86
|
+
const wrappingDivRef = useRef(null);
|
|
87
|
+
const { root } = useGetDomRoot(domRoot, wrappingDivRef);
|
|
85
88
|
|
|
86
89
|
const handleEscKeyPress = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
87
90
|
if (!disableEscapeKeyDown && event.key === "Escape") {
|
|
@@ -92,50 +95,54 @@ const BaseModalComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
92
95
|
|
|
93
96
|
const handleBackdropClick = () => !disableBackdrop && onClose && onClose();
|
|
94
97
|
|
|
95
|
-
return
|
|
96
|
-
<div
|
|
97
|
-
{
|
|
98
|
-
ref={ref}
|
|
99
|
-
id={id}
|
|
100
|
-
className={`${classes["modal"]} ${open ? classes["visible"] : ""} ${className}`}
|
|
101
|
-
role="dialog"
|
|
102
|
-
aria-modal="true"
|
|
103
|
-
aria-labelledby={labelledby || labelId(id)}
|
|
104
|
-
aria-describedby={describedby || descriptionId(id)}
|
|
105
|
-
aria-hidden={!open}
|
|
106
|
-
tabIndex={-1}
|
|
107
|
-
data-hidden={!open}
|
|
108
|
-
onKeyDown={handleEscKeyPress}
|
|
109
|
-
style={{ zIndex }}
|
|
110
|
-
>
|
|
111
|
-
<div
|
|
112
|
-
{...backdropProps}
|
|
113
|
-
className={`${classes["backdrop"]} ${backdropProps?.className ?? ""}`}
|
|
114
|
-
onClick={handleBackdropClick}
|
|
115
|
-
></div>
|
|
116
|
-
{forceContainerOpen ? (
|
|
98
|
+
return (
|
|
99
|
+
<div ref={wrappingDivRef}>
|
|
100
|
+
{createPortal(
|
|
117
101
|
<div
|
|
118
|
-
{...
|
|
102
|
+
{...rest}
|
|
103
|
+
ref={ref}
|
|
104
|
+
id={id}
|
|
105
|
+
className={`${classes["modal"]} ${open ? classes["visible"] : ""} ${className}`}
|
|
106
|
+
role="dialog"
|
|
107
|
+
aria-modal="true"
|
|
108
|
+
aria-labelledby={labelledby || labelId(id)}
|
|
109
|
+
aria-describedby={describedby || descriptionId(id)}
|
|
119
110
|
aria-hidden={!open}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
tabIndex={-1}
|
|
112
|
+
data-hidden={!open}
|
|
113
|
+
onKeyDown={handleEscKeyPress}
|
|
114
|
+
style={{ zIndex }}
|
|
123
115
|
>
|
|
124
|
-
{children}
|
|
125
|
-
</div>
|
|
126
|
-
) : (
|
|
127
|
-
open && (
|
|
128
116
|
<div
|
|
129
|
-
{...
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
117
|
+
{...backdropProps}
|
|
118
|
+
className={`${classes["backdrop"]} ${backdropProps?.className ?? ""}`}
|
|
119
|
+
onClick={handleBackdropClick}
|
|
120
|
+
></div>
|
|
121
|
+
{forceContainerOpen ? (
|
|
122
|
+
<div
|
|
123
|
+
{...containerProps}
|
|
124
|
+
aria-hidden={!open}
|
|
125
|
+
hidden={!open}
|
|
126
|
+
style={{ zIndex: zIndex && zIndex + 1 }}
|
|
127
|
+
className={`${classes["container"]} ${containerProps?.className ?? ""}`}
|
|
128
|
+
>
|
|
129
|
+
{children}
|
|
130
|
+
</div>
|
|
131
|
+
) : (
|
|
132
|
+
open && (
|
|
133
|
+
<div
|
|
134
|
+
{...containerProps}
|
|
135
|
+
style={{ zIndex: zIndex && zIndex + 1 }}
|
|
136
|
+
className={`${classes["container"]} ${containerProps?.className ?? ""}`}
|
|
137
|
+
>
|
|
138
|
+
{children}
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
)}
|
|
142
|
+
</div>,
|
|
143
|
+
root
|
|
136
144
|
)}
|
|
137
|
-
</div
|
|
138
|
-
domRoot
|
|
145
|
+
</div>
|
|
139
146
|
);
|
|
140
147
|
};
|
|
141
148
|
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import React, { ReactNode, useState } from "react";
|
|
17
|
+
import React, { ReactNode, useRef, useState } from "react";
|
|
18
18
|
import { createPortal } from "react-dom";
|
|
19
19
|
import { SnackbarContextProvider } from "./SnackbarStateProvider";
|
|
20
20
|
import { Actions, SnackbarOptionsProps, Variant } from "../interfaces";
|
|
21
21
|
import { Placement, SnackbarContainer } from "../SnackbarContainer/SnackbarContainer";
|
|
22
22
|
import { generateID } from "../../../util/helper";
|
|
23
23
|
import { SnackbarItem } from "../SnackbarItem/SnackbarItem";
|
|
24
|
+
import { useGetDomRoot } from "../../../hooks/useGetDomRoot";
|
|
24
25
|
|
|
25
26
|
/** Short msg is when only title is provided. Long one when content or/and actions are provided (or type is error). */
|
|
26
27
|
interface Duration {
|
|
@@ -55,12 +56,14 @@ export const SnackbarProvider = (
|
|
|
55
56
|
placement = { vertical: "bottom", horizontal: "center" },
|
|
56
57
|
autoHideDuration = { long: 8000, short: 4000 },
|
|
57
58
|
stackSize = 3,
|
|
58
|
-
domRoot
|
|
59
|
+
domRoot,
|
|
59
60
|
children,
|
|
60
61
|
className
|
|
61
62
|
}: Props = { closeButtonTitle: "" }
|
|
62
63
|
) => {
|
|
63
64
|
const [snackbars, setSnackbars] = useState<Item[]>([]);
|
|
65
|
+
const wrappingDivRef = useRef(null);
|
|
66
|
+
const { root } = useGetDomRoot(domRoot, wrappingDivRef);
|
|
64
67
|
|
|
65
68
|
const addSnackbar = (item: Item) => {
|
|
66
69
|
setSnackbars(items => [...items, item]);
|
|
@@ -149,7 +152,7 @@ export const SnackbarProvider = (
|
|
|
149
152
|
<SnackbarContainer placement={placement} className={className}>
|
|
150
153
|
{snackbarList}
|
|
151
154
|
</SnackbarContainer>,
|
|
152
|
-
|
|
155
|
+
root
|
|
153
156
|
);
|
|
154
157
|
|
|
155
158
|
return (
|
|
@@ -163,7 +166,7 @@ export const SnackbarProvider = (
|
|
|
163
166
|
}}
|
|
164
167
|
>
|
|
165
168
|
{children}
|
|
166
|
-
{snackbarPortal}
|
|
169
|
+
<div ref={wrappingDivRef}>{snackbarPortal}</div>
|
|
167
170
|
</SnackbarContextProvider>
|
|
168
171
|
);
|
|
169
172
|
};
|
package/src/Tooltip/Tooltip.tsx
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
|
|
17
17
|
import React, {
|
|
18
18
|
ComponentPropsWithRef,
|
|
19
|
+
createRef,
|
|
19
20
|
ForwardRefRenderFunction,
|
|
20
21
|
ReactElement,
|
|
21
22
|
ReactNode,
|
|
23
|
+
RefObject,
|
|
22
24
|
useEffect,
|
|
23
25
|
useLayoutEffect,
|
|
24
26
|
useRef,
|
|
@@ -29,6 +31,7 @@ import classes from "./Tooltip.module.scss";
|
|
|
29
31
|
import { generateID } from "../util/helper";
|
|
30
32
|
import { Offset, Placement, usePosition } from "../hooks/usePosition";
|
|
31
33
|
import { createPortal } from "react-dom";
|
|
34
|
+
import { useGetDomRoot } from "../hooks/useGetDomRoot";
|
|
32
35
|
|
|
33
36
|
export interface Props extends ComponentPropsWithRef<"div"> {
|
|
34
37
|
label: string | ReactNode;
|
|
@@ -58,7 +61,7 @@ const TooltipComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
58
61
|
placement = defaultPosition.placement,
|
|
59
62
|
offset = defaultPosition.offset,
|
|
60
63
|
transformOrigin = defaultPosition.transformOrigin,
|
|
61
|
-
domRoot
|
|
64
|
+
domRoot,
|
|
62
65
|
label,
|
|
63
66
|
...rest
|
|
64
67
|
}: Props,
|
|
@@ -67,6 +70,9 @@ const TooltipComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
67
70
|
const [identifier] = useState(generateID());
|
|
68
71
|
const [visible, setVisible] = useState(false);
|
|
69
72
|
|
|
73
|
+
const wrappingDivRef = (ref as RefObject<HTMLDivElement>) || createRef<HTMLDivElement>();
|
|
74
|
+
const { root } = useGetDomRoot(domRoot, wrappingDivRef);
|
|
75
|
+
|
|
70
76
|
const relativeElement = useRef<HTMLDivElement>(null);
|
|
71
77
|
const elementToBePositioned = useRef<HTMLDivElement>(null);
|
|
72
78
|
|
|
@@ -123,7 +129,7 @@ const TooltipComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
123
129
|
};
|
|
124
130
|
|
|
125
131
|
return (
|
|
126
|
-
<div {...rest} ref={
|
|
132
|
+
<div {...rest} ref={wrappingDivRef} className={`${classes.wrapper} ${className ?? ""}`}>
|
|
127
133
|
{renderChildren()}
|
|
128
134
|
<div className={`${classes["tooltip-wrapper"]}`}>
|
|
129
135
|
<Icon
|
|
@@ -150,7 +156,7 @@ const TooltipComponent: ForwardRefRenderFunction<HTMLDivElement, Props> = (
|
|
|
150
156
|
>
|
|
151
157
|
{children}
|
|
152
158
|
</div>,
|
|
153
|
-
|
|
159
|
+
root
|
|
154
160
|
)}
|
|
155
161
|
</div>
|
|
156
162
|
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { useEffect, useState } from "react";
|
|
18
|
+
|
|
19
|
+
export const useGetDomRoot = (
|
|
20
|
+
passedDomRoot: HTMLElement | undefined,
|
|
21
|
+
relativeElement: React.RefObject<HTMLDivElement> | null
|
|
22
|
+
) => {
|
|
23
|
+
const [root, setRoot] = useState<HTMLElement>(document.body);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (relativeElement && relativeElement.current && !passedDomRoot) {
|
|
27
|
+
const closestBaseStylingWrapper = relativeElement.current.closest(".basestyling-wrapper");
|
|
28
|
+
|
|
29
|
+
if (closestBaseStylingWrapper) {
|
|
30
|
+
setRoot(closestBaseStylingWrapper as HTMLElement);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
} else if (passedDomRoot) {
|
|
34
|
+
setRoot(passedDomRoot);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}, [relativeElement]);
|
|
38
|
+
|
|
39
|
+
return { root };
|
|
40
|
+
};
|
package/src/hooks/usePosition.ts
CHANGED
|
@@ -330,7 +330,8 @@ export const usePosition = (providedConfigObject: ConfigObject = defaultConfigOb
|
|
|
330
330
|
};
|
|
331
331
|
|
|
332
332
|
const calculatePosition = useDebouncedCallback(() => {
|
|
333
|
-
if (!configObject.relativeElement?.current)
|
|
333
|
+
if (!configObject.relativeElement?.current || !configObject.elementToBePositioned?.current)
|
|
334
|
+
return;
|
|
334
335
|
const relativeElRect = (configObject.relativeElement!
|
|
335
336
|
.current as HTMLElement)!.getBoundingClientRect();
|
|
336
337
|
const elementToBePositionedDimensions: Dimensions = {
|