@onewelcome/react-lib-components 1.8.3 → 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.
Files changed (35) hide show
  1. package/dist/Button/BaseButton.d.ts +2 -1
  2. package/dist/Button/Button.d.ts +1 -1
  3. package/dist/Button/IconButton.d.ts +1 -1
  4. package/dist/Button/Spinner.d.ts +2 -0
  5. package/dist/Notifications/BaseModal/BaseModal.d.ts +1 -1
  6. package/dist/_BaseStyling_/BaseStyling.d.ts +1 -1
  7. package/dist/hooks/useGetDomRoot.d.ts +3 -0
  8. package/dist/react-lib-components.cjs.development.js +93 -32
  9. package/dist/react-lib-components.cjs.development.js.map +1 -1
  10. package/dist/react-lib-components.cjs.production.min.js +1 -1
  11. package/dist/react-lib-components.cjs.production.min.js.map +1 -1
  12. package/dist/react-lib-components.esm.js +94 -33
  13. package/dist/react-lib-components.esm.js.map +1 -1
  14. package/dist/util/helper.d.ts +1 -0
  15. package/package.json +14 -14
  16. package/src/Button/BaseButton.module.scss +24 -0
  17. package/src/Button/BaseButton.test.tsx +12 -0
  18. package/src/Button/BaseButton.tsx +17 -5
  19. package/src/Button/Spinner.tsx +33 -0
  20. package/src/ContextMenu/ContextMenu.tsx +18 -3
  21. package/src/DataGrid/DataGridBody/__snapshots__/DataGridBody.test.tsx.snap +4 -4
  22. package/src/Form/FileUpload/FileUpload.module.scss +9 -2
  23. package/src/Form/FileUpload/FileUpload.tsx +35 -33
  24. package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +1 -0
  25. package/src/Notifications/BaseModal/BaseModal.tsx +48 -41
  26. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.module.scss +1 -1
  27. package/src/Notifications/Snackbar/SnackbarProvider/SnackbarProvider.tsx +7 -4
  28. package/src/Tooltip/Tooltip.tsx +9 -3
  29. package/src/_BaseStyling_/BaseStyling.tsx +14 -6
  30. package/src/hooks/useGetDomRoot.ts +40 -0
  31. package/src/hooks/usePosition.ts +2 -1
  32. package/src/hooks/useUploadFile.test.ts +2 -2
  33. package/src/hooks/useUploadFile.tsx +8 -5
  34. package/src/util/helper.test.tsx +16 -1
  35. package/src/util/helper.tsx +9 -0
@@ -12,4 +12,5 @@ export declare const getValueByPath: (obj: {
12
12
  }, path: string) => any;
13
13
  /** Source: https://stackoverflow.com/a/42769683/5084110 */
14
14
  export declare const remToPx: (rem: number) => number;
15
+ export declare const isJsonString: (str: any) => boolean;
15
16
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "homepage": "http://onewelcome.github.io/react-lib-components",
3
3
  "name": "@onewelcome/react-lib-components",
4
- "version": "1.8.3",
4
+ "version": "1.9.1",
5
5
  "license": "Apache-2.0",
6
6
  "author": "OneWelcome B.V.",
7
7
  "main": "dist/index.js",
@@ -53,7 +53,7 @@
53
53
  }
54
54
  ],
55
55
  "devDependencies": {
56
- "@babel/core": "^7.21.0",
56
+ "@babel/core": "^7.21.3",
57
57
  "@mdx-js/react": "^1.6.22",
58
58
  "@onewelcome/eslint-config-shared-codestyle": "^9.0.3",
59
59
  "@size-limit/preset-small-lib": "^8.2.4",
@@ -80,13 +80,13 @@
80
80
  "@types/react-dom": "^17.0.18",
81
81
  "@types/react-router": "^5.1.20",
82
82
  "@types/react-router-dom": "^5.3.3",
83
- "@typescript-eslint/eslint-plugin": "^5.53.0",
84
- "@typescript-eslint/parser": "^5.53.0",
83
+ "@typescript-eslint/eslint-plugin": "^5.56.0",
84
+ "@typescript-eslint/parser": "^5.56.0",
85
85
  "babel-loader": "^9.1.2",
86
- "chromatic": "^6.17.1",
86
+ "chromatic": "^6.17.2",
87
87
  "dts-cli": "^1.6.3",
88
- "eslint": "^8.34.0",
89
- "eslint-config-prettier": "^8.6.0",
88
+ "eslint": "^8.36.0",
89
+ "eslint-config-prettier": "^8.8.0",
90
90
  "eslint-plugin-cypress": "^2.12.1",
91
91
  "eslint-plugin-jest": "^27.2.1",
92
92
  "eslint-plugin-license-header": "^0.6.0",
@@ -95,19 +95,19 @@
95
95
  "husky": "^8.0.3",
96
96
  "identity-obj-proxy": "^3.0.0",
97
97
  "jest-junit": "^15.0.0",
98
- "lint-staged": "^13.1.2",
98
+ "lint-staged": "^13.2.0",
99
99
  "npm-run-all": "^4.1.5",
100
- "prettier": "^2.8.4",
100
+ "prettier": "^2.8.6",
101
101
  "react": "^17.0.2",
102
102
  "react-dom": "^17.0.2",
103
103
  "react-is": "^18.2.0",
104
- "react-router": "^6.6.2",
105
- "react-router-dom": "^6.8.2",
104
+ "react-router": "^6.9.0",
105
+ "react-router-dom": "^6.9.0",
106
106
  "rollup-plugin-cleanup": "^3.2.1",
107
107
  "rollup-plugin-styles": "^4.0.0",
108
- "sass": "^1.58.3",
109
- "size-limit": "^8.1.1",
110
- "style-loader": "^3.3.1",
108
+ "sass": "^1.60.0",
109
+ "size-limit": "^8.2.4",
110
+ "style-loader": "^3.3.2",
111
111
  "tslib": "^2.5.0",
112
112
  "typescript": "^4.9.5"
113
113
  }
@@ -18,4 +18,28 @@
18
18
 
19
19
  .button {
20
20
  @include mixins.buttonBase();
21
+ position: relative;
22
+
23
+ .content-hidden {
24
+ visibility: hidden;
25
+ display: flex;
26
+ }
27
+ }
28
+
29
+ .spinner {
30
+ position: absolute;
31
+ top: calc(50% - 0.75rem);
32
+ left: calc(50% - 0.75rem);
33
+ transform: translate(-50%, -50%);
34
+ animation: spin 1s infinite linear;
35
+
36
+ @keyframes spin {
37
+ 0% {
38
+ transform: rotate(0deg);
39
+ }
40
+
41
+ 100% {
42
+ transform: rotate(360deg);
43
+ }
44
+ }
21
45
  }
@@ -75,6 +75,18 @@ describe("Properties of the button", () => {
75
75
  expect(onClickHandler).toHaveBeenCalledTimes(0);
76
76
  });
77
77
 
78
+ it("when loading onClick function should not have been called", async () => {
79
+ const onClickHandler = jest.fn();
80
+ const { baseButton } = createBaseButton(defaultParams => ({
81
+ ...defaultParams,
82
+ loading: true,
83
+ onClick: onClickHandler
84
+ }));
85
+
86
+ await userEvent.click(baseButton);
87
+ expect(onClickHandler).toHaveBeenCalledTimes(0);
88
+ });
89
+
78
90
  it('should have the class "TESTING"', () => {
79
91
  const { baseButton } = createBaseButton(defaultParams => ({
80
92
  ...defaultParams,
@@ -14,21 +14,23 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import React, { ForwardRefRenderFunction, ComponentPropsWithRef } from "react";
17
+ import React, { ForwardRefRenderFunction, ComponentPropsWithRef, Fragment } from "react";
18
18
  import classes from "./BaseButton.module.scss";
19
+ import { Spinner } from "./Spinner";
19
20
 
20
21
  export interface Props extends ComponentPropsWithRef<"button"> {
21
22
  type?: "submit" | "button" | "reset";
22
23
  disabled?: boolean;
24
+ loading?: boolean;
23
25
  color?: "primary" | "secondary" | "tertiary" | "default";
24
26
  }
25
27
 
26
28
  const BaseButtonComponent: ForwardRefRenderFunction<HTMLButtonElement, Props> = (
27
- { children, type = "button", className, ...rest },
29
+ { children, type = "button", className, loading, disabled, ...rest },
28
30
  ref
29
31
  ) => {
30
32
  const validTypes = ["submit", "button", "reset"];
31
-
33
+ const isDisabled = disabled || loading;
32
34
  if (!validTypes.includes(type))
33
35
  throw new Error(
34
36
  `You have entered an invalid button type. Expected 'submit', 'button' or 'reset' got ${type}`
@@ -37,11 +39,21 @@ const BaseButtonComponent: ForwardRefRenderFunction<HTMLButtonElement, Props> =
37
39
  return (
38
40
  <button
39
41
  {...rest}
42
+ disabled={isDisabled}
40
43
  ref={ref}
41
44
  type={type}
42
- className={`${classes.button} ${className ? className : ""}`}
45
+ className={`${classes.button} ${loading ? classes.loading : ""} ${
46
+ className ? className : ""
47
+ }`}
43
48
  >
44
- {children}
49
+ {loading ? (
50
+ <Fragment>
51
+ <div className={classes["content-hidden"]}>{children}</div>
52
+ <Spinner className={classes["spinner"]} />
53
+ </Fragment>
54
+ ) : (
55
+ children
56
+ )}
45
57
  </button>
46
58
  );
47
59
  };
@@ -0,0 +1,33 @@
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 React from "react";
18
+
19
+ export const Spinner: React.FC<React.SVGProps<SVGSVGElement>> = props => (
20
+ <svg
21
+ {...props}
22
+ width="24"
23
+ height="24"
24
+ viewBox="0 0 24 24"
25
+ fill="none"
26
+ xmlns="http://www.w3.org/2000/svg"
27
+ >
28
+ <path
29
+ d="M24 12C24 13.8937 23.5518 15.7606 22.6921 17.4479C21.8323 19.1352 20.5855 20.5951 19.0534 21.7082C17.5214 22.8213 15.7476 23.556 13.8772 23.8523C12.0068 24.1485 10.0928 23.9979 8.2918 23.4127C6.49076 22.8275 4.85378 21.8243 3.51472 20.4853C2.17565 19.1462 1.17251 17.5092 0.587322 15.7082C0.00212849 13.9072 -0.148504 11.9932 0.14774 10.1228C0.443984 8.25238 1.17869 6.47863 2.2918 4.94658L3.91307 6.1245C2.98585 7.4007 2.37384 8.87823 2.12707 10.4363C1.8803 11.9943 2.00577 13.5887 2.49324 15.0889C2.9807 16.5892 3.81632 17.9528 4.93176 19.0682C6.0472 20.1837 7.4108 21.0193 8.91107 21.5068C10.4113 21.9942 12.0057 22.1197 13.5637 21.8729C15.1218 21.6262 16.5993 21.0141 17.8755 20.0869C19.1517 19.1597 20.1903 17.9436 20.9065 16.5381C21.6227 15.1326 21.996 13.5775 21.996 12H24Z"
30
+ fill="#5D607E"
31
+ />
32
+ </svg>
33
+ );
@@ -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 = document.body,
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 {...rest} ref={ref} onKeyDown={onArrowNavigation} className={classes["context-menu"]}>
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
- domRoot
242
+ root
228
243
  )}
229
244
  </div>
230
245
  );
@@ -45,7 +45,7 @@ Array [
45
45
  aria-controls="consent_menu_Paweł-menu"
46
46
  aria-expanded="false"
47
47
  aria-haspopup="true"
48
- class="button icon-button text default button-m"
48
+ class="button icon-button text default button-m"
49
49
  id="consent_menu_Paweł"
50
50
  tabindex="0"
51
51
  type="button"
@@ -108,7 +108,7 @@ Array [
108
108
  aria-controls="consent_menu_Michał-menu"
109
109
  aria-expanded="false"
110
110
  aria-haspopup="true"
111
- class="button icon-button text default button-m"
111
+ class="button icon-button text default button-m"
112
112
  id="consent_menu_Michał"
113
113
  tabindex="0"
114
114
  type="button"
@@ -171,7 +171,7 @@ Array [
171
171
  aria-controls="consent_menu_Daniel-menu"
172
172
  aria-expanded="false"
173
173
  aria-haspopup="true"
174
- class="button icon-button text default button-m"
174
+ class="button icon-button text default button-m"
175
175
  id="consent_menu_Daniel"
176
176
  tabindex="0"
177
177
  type="button"
@@ -234,7 +234,7 @@ Array [
234
234
  aria-controls="consent_menu_Jasha-menu"
235
235
  aria-expanded="false"
236
236
  aria-haspopup="true"
237
- class="button icon-button text default button-m"
237
+ class="button icon-button text default button-m"
238
238
  id="consent_menu_Jasha"
239
239
  tabindex="0"
240
240
  type="button"
@@ -39,8 +39,7 @@
39
39
  }
40
40
  &.error {
41
41
  span[data-icon-status],
42
- .file-upload-title,
43
- .file-selector-sub-text {
42
+ .file-upload-title {
44
43
  color: var(--error);
45
44
  }
46
45
  }
@@ -63,6 +62,14 @@
63
62
  }
64
63
  }
65
64
 
65
+ .file-selector-sub-text {
66
+ color: var(--greyed-out);
67
+ padding: 0 1.25rem;
68
+ &.error {
69
+ color: var(--error);
70
+ }
71
+ }
72
+
66
73
  .file-select {
67
74
  display: flex;
68
75
  align-items: center;
@@ -136,7 +136,7 @@ const FileUploadComponent: ForwardRefRenderFunction<HTMLInputElement, Props> = (
136
136
 
137
137
  let err = false;
138
138
  if (maxFileSize && file.size && file.size >= maxFileSize) {
139
- const mb = (file.size / (1024 * 1024)).toFixed(2);
139
+ const mb = (maxFileSize / (1024 * 1024)).toFixed(2);
140
140
  result.error =
141
141
  exceedingMaxSizeErrorText ||
142
142
  `The maximum allowed file size is ${mb}MB. Upload a smaller file.`;
@@ -188,40 +188,42 @@ const FileUploadComponent: ForwardRefRenderFunction<HTMLInputElement, Props> = (
188
188
 
189
189
  return (
190
190
  <div className={classes["file-upload-wrapper"]} {...wrapperProps}>
191
- <div
192
- className={dropzoneClassNames.join(" ")}
193
- onDragOver={e => !disabled && handleOnDragOver(e)}
194
- onDragLeave={e => !disabled && handleOnDragLeave(e)}
195
- onDrop={e => !disabled && handleOnDrop(e)}
196
- >
197
- <Typography variant="body-bold" className={classes["file-upload-title"]} ref={labelRef}>
198
- {title}
199
- </Typography>
200
- <div className={classes["file-select"]}>
201
- <Icon className={"drop-file-icon"} icon={Icons.FileUpload} />
202
- <Typography variant="body" className={"drag-and-drop-text"}>
203
- {dragAndDropText}
191
+ <div className={classes["dropzone-wrapper"]}>
192
+ <div
193
+ className={dropzoneClassNames.join(" ")}
194
+ onDragOver={e => !disabled && handleOnDragOver(e)}
195
+ onDragLeave={e => !disabled && handleOnDragLeave(e)}
196
+ onDrop={e => !disabled && handleOnDrop(e)}
197
+ >
198
+ <Typography variant="body-bold" className={classes["file-upload-title"]} ref={labelRef}>
199
+ {title}
204
200
  </Typography>
205
- <div className={classes["file-upload-btn"]}>
206
- <Button variant="outline" disabled={disabled}>
207
- {selectButtonText}
208
- <input
209
- className={classes["upload-input"]}
210
- {...rest}
211
- ref={ref}
212
- aria-labelledby={labeledBy}
213
- type="file"
214
- name={name}
215
- {...(multiple && { multiple: true })}
216
- disabled={disabled}
217
- accept={accept}
218
- onChange={onInputChange}
219
- spellCheck={rest.spellCheck || false}
220
- />
221
- </Button>
201
+ <div className={classes["file-select"]}>
202
+ <Icon className={"drop-file-icon"} icon={Icons.FileUpload} />
203
+ <Typography variant="body" className={"drag-and-drop-text"}>
204
+ {dragAndDropText}
205
+ </Typography>
206
+ <div className={classes["file-upload-btn"]}>
207
+ <Button variant="outline" disabled={disabled}>
208
+ {selectButtonText}
209
+ <input
210
+ className={classes["upload-input"]}
211
+ {...rest}
212
+ ref={ref}
213
+ aria-labelledby={labeledBy}
214
+ type="file"
215
+ name={name}
216
+ {...(multiple && { multiple: true })}
217
+ disabled={disabled}
218
+ accept={accept}
219
+ onChange={onInputChange}
220
+ spellCheck={rest.spellCheck || false}
221
+ />
222
+ </Button>
223
+ </div>
224
+ {!disabled && icon}
225
+ <span className={classes["outline"]}></span>
222
226
  </div>
223
- {!disabled && icon}
224
- <span className={classes["outline"]}></span>
225
227
  </div>
226
228
  {subText && (
227
229
  <Typography variant={"sub-text"} className={subTextClass.join(" ")}>
@@ -42,6 +42,7 @@ input {
42
42
  [data-prefix],
43
43
  [data-suffix] {
44
44
  transform: translateY(-0.125rem);
45
+ font-family: var(--font-family);
45
46
  }
46
47
 
47
48
  [data-prefix] + input {
@@ -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 = document.body,
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 createPortal(
96
- <div
97
- {...rest}
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
- {...containerProps}
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
- hidden={!open}
121
- style={{ zIndex: zIndex && zIndex + 1 }}
122
- className={`${classes["container"]} ${containerProps?.className ?? ""}`}
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
- {...containerProps}
130
- style={{ zIndex: zIndex && zIndex + 1 }}
131
- className={`${classes["container"]} ${containerProps?.className ?? ""}`}
132
- >
133
- {children}
134
- </div>
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
 
@@ -19,7 +19,7 @@
19
19
  display: flex;
20
20
  justify-content: flex-end;
21
21
 
22
- & * + * {
22
+ & > * {
23
23
  margin-left: 2rem;
24
24
  }
25
25
  }
@@ -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 = document.body,
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
- domRoot
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
  };
@@ -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 = document.body,
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={ref} className={`${classes.wrapper} ${className ?? ""}`}>
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
- domRoot
159
+ root
154
160
  )}
155
161
  </div>
156
162
  </div>