@scm-manager/ui-components 2.39.1 → 2.39.2-20220912-102715

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-manager/ui-components",
3
- "version": "2.39.1",
3
+ "version": "2.39.2-20220912-102715",
4
4
  "description": "UI Components for SCM-Manager and its plugins",
5
5
  "main": "src/index.ts",
6
6
  "files": [
@@ -20,14 +20,14 @@
20
20
  "update-storyshots": "jest --testPathPattern=\"storyshots.test.ts\" --collectCoverage=false -u"
21
21
  },
22
22
  "devDependencies": {
23
- "@scm-manager/ui-syntaxhighlighting": "2.39.1",
24
- "@scm-manager/ui-text": "2.39.1",
23
+ "@scm-manager/ui-syntaxhighlighting": "2.39.2-20220912-102715",
24
+ "@scm-manager/ui-text": "2.39.2-20220912-102715",
25
25
  "@scm-manager/babel-preset": "^2.13.1",
26
26
  "@scm-manager/eslint-config": "^2.16.0",
27
27
  "@scm-manager/jest-preset": "^2.13.0",
28
28
  "@scm-manager/prettier-config": "^2.10.1",
29
29
  "@scm-manager/tsconfig": "^2.13.0",
30
- "@scm-manager/ui-tests": "2.39.1",
30
+ "@scm-manager/ui-tests": "2.39.2-20220912-102715",
31
31
  "@storybook/addon-actions": "^6.4.20",
32
32
  "@storybook/addon-essentials": "^6.4.20",
33
33
  "@storybook/addon-interactions": "^6.4.20",
@@ -66,9 +66,9 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@headlessui/react": "^1.4.3",
69
- "@scm-manager/ui-api": "2.39.1",
70
- "@scm-manager/ui-extensions": "2.39.1",
71
- "@scm-manager/ui-types": "2.39.1",
69
+ "@scm-manager/ui-api": "2.39.2-20220912-102715",
70
+ "@scm-manager/ui-extensions": "2.39.2-20220912-102715",
71
+ "@scm-manager/ui-types": "2.39.2-20220912-102715",
72
72
  "classnames": "^2.2.6",
73
73
  "date-fns": "^2.4.1",
74
74
  "deepmerge": "^4.2.2",
@@ -1677,6 +1677,26 @@ exports[`Storyshots Footer Default 1`] = `
1677
1677
  footer.support.enterprise
1678
1678
  </a>
1679
1679
  </li>
1680
+ <li>
1681
+ <a
1682
+ className=""
1683
+ href="https://community.cloudogu.com/c/scm-manager/bug-reports-scmm"
1684
+ rel="noopener noreferrer"
1685
+ target="_blank"
1686
+ >
1687
+ footer.support.bugReport
1688
+ </a>
1689
+ </li>
1690
+ <li>
1691
+ <a
1692
+ className=""
1693
+ href="https://community.cloudogu.com/c/scm-manager/feature-requests-scmm"
1694
+ rel="noopener noreferrer"
1695
+ target="_blank"
1696
+ >
1697
+ footer.support.featureRequest
1698
+ </a>
1699
+ </li>
1680
1700
  </ul>
1681
1701
  </section>
1682
1702
  </div>
@@ -1843,6 +1863,26 @@ exports[`Storyshots Footer Full 1`] = `
1843
1863
  footer.support.enterprise
1844
1864
  </a>
1845
1865
  </li>
1866
+ <li>
1867
+ <a
1868
+ className=""
1869
+ href="https://community.cloudogu.com/c/scm-manager/bug-reports-scmm"
1870
+ rel="noopener noreferrer"
1871
+ target="_blank"
1872
+ >
1873
+ footer.support.bugReport
1874
+ </a>
1875
+ </li>
1876
+ <li>
1877
+ <a
1878
+ className=""
1879
+ href="https://community.cloudogu.com/c/scm-manager/feature-requests-scmm"
1880
+ rel="noopener noreferrer"
1881
+ target="_blank"
1882
+ >
1883
+ footer.support.featureRequest
1884
+ </a>
1885
+ </li>
1846
1886
  <li>
1847
1887
  <a
1848
1888
  className=""
@@ -1990,6 +2030,26 @@ exports[`Storyshots Footer With Avatar 1`] = `
1990
2030
  footer.support.enterprise
1991
2031
  </a>
1992
2032
  </li>
2033
+ <li>
2034
+ <a
2035
+ className=""
2036
+ href="https://community.cloudogu.com/c/scm-manager/bug-reports-scmm"
2037
+ rel="noopener noreferrer"
2038
+ target="_blank"
2039
+ >
2040
+ footer.support.bugReport
2041
+ </a>
2042
+ </li>
2043
+ <li>
2044
+ <a
2045
+ className=""
2046
+ href="https://community.cloudogu.com/c/scm-manager/feature-requests-scmm"
2047
+ rel="noopener noreferrer"
2048
+ target="_blank"
2049
+ >
2050
+ footer.support.featureRequest
2051
+ </a>
2052
+ </li>
1993
2053
  </ul>
1994
2054
  </section>
1995
2055
  </div>
@@ -2148,6 +2208,26 @@ exports[`Storyshots Footer With Plugin Links 1`] = `
2148
2208
  footer.support.enterprise
2149
2209
  </a>
2150
2210
  </li>
2211
+ <li>
2212
+ <a
2213
+ className=""
2214
+ href="https://community.cloudogu.com/c/scm-manager/bug-reports-scmm"
2215
+ rel="noopener noreferrer"
2216
+ target="_blank"
2217
+ >
2218
+ footer.support.bugReport
2219
+ </a>
2220
+ </li>
2221
+ <li>
2222
+ <a
2223
+ className=""
2224
+ href="https://community.cloudogu.com/c/scm-manager/feature-requests-scmm"
2225
+ rel="noopener noreferrer"
2226
+ target="_blank"
2227
+ >
2228
+ footer.support.featureRequest
2229
+ </a>
2230
+ </li>
2151
2231
  <li>
2152
2232
  <a
2153
2233
  className=""
@@ -71378,7 +71458,7 @@ exports[`Storyshots Secondary Navigation Active when match 1`] = `
71378
71458
  className="column is-3"
71379
71459
  >
71380
71460
  <aside
71381
- className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 NSEld menu"
71461
+ className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 cZyrQa menu"
71382
71462
  >
71383
71463
  <div>
71384
71464
  <p
@@ -71440,7 +71520,7 @@ exports[`Storyshots Secondary Navigation Default 1`] = `
71440
71520
  className="column is-3"
71441
71521
  >
71442
71522
  <aside
71443
- className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 NSEld menu"
71523
+ className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 cZyrQa menu"
71444
71524
  >
71445
71525
  <div>
71446
71526
  <p
@@ -71502,7 +71582,7 @@ exports[`Storyshots Secondary Navigation Extension Point 1`] = `
71502
71582
  className="column is-3"
71503
71583
  >
71504
71584
  <aside
71505
- className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 NSEld menu"
71585
+ className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 cZyrQa menu"
71506
71586
  >
71507
71587
  <div>
71508
71588
  <p
@@ -71590,7 +71670,7 @@ exports[`Storyshots Secondary Navigation Sub Navigation 1`] = `
71590
71670
  className="column is-3"
71591
71671
  >
71592
71672
  <aside
71593
- className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 NSEld menu"
71673
+ className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 cZyrQa menu"
71594
71674
  >
71595
71675
  <div>
71596
71676
  <p
@@ -22,7 +22,8 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
  import React, { FC } from "react";
25
- import { Links, Me } from "@scm-manager/ui-types";
25
+ import { Feedback, Links, Me } from "@scm-manager/ui-types";
26
+ import { useIndex } from "@scm-manager/ui-api";
26
27
  import { ExtensionPoint, extensionPoints, useBinder } from "@scm-manager/ui-extensions";
27
28
  import { AvatarImage } from "../avatar";
28
29
  import NavLink from "../navigation/NavLink";
@@ -80,6 +81,7 @@ const TitleWithAvatar: FC<TitleWithAvatarProps> = ({ me }) => (
80
81
  const Footer: FC<Props> = ({ me, version, links }) => {
81
82
  const [t] = useTranslation("commons");
82
83
  const binder = useBinder();
84
+ const index = useIndex();
83
85
 
84
86
  const extensionProps = { me, url: "/me", links };
85
87
  let meSectionTile;
@@ -124,6 +126,18 @@ const Footer: FC<Props> = ({ me, version, links }) => {
124
126
  to="https://cloudogu.com/en/scm-manager-enterprise/"
125
127
  label={t("footer.support.enterprise")}
126
128
  />
129
+ {!(index.data?._embedded?.feedback as Feedback)?.disabled ? (
130
+ <>
131
+ <ExternalNavLink
132
+ to="https://community.cloudogu.com/c/scm-manager/bug-reports-scmm"
133
+ label={t("footer.support.bugReport")}
134
+ />
135
+ <ExternalNavLink
136
+ to="https://community.cloudogu.com/c/scm-manager/feature-requests-scmm"
137
+ label={t("footer.support.featureRequest")}
138
+ />
139
+ </>
140
+ ) : null}
127
141
  <ExtensionPoint name="footer.support" props={extensionProps} renderAll={true} />
128
142
  </FooterSection>
129
143
  </div>
@@ -28,10 +28,6 @@ type Props = {
28
28
  authenticated?: boolean;
29
29
  };
30
30
 
31
- const SmallHeader: FC = ({ children }) => {
32
- return <div className="has-scm-background">{children}</div>;
33
- };
34
-
35
31
  const LargeHeader: FC = () => {
36
32
  return (
37
33
  <div className="hero has-scm-background is-small">
@@ -50,7 +46,7 @@ const LargeHeader: FC = () => {
50
46
 
51
47
  const Header: FC<Props> = ({ authenticated, children }) => {
52
48
  if (authenticated) {
53
- return <SmallHeader>{children}</SmallHeader>;
49
+ return <>{children}</>;
54
50
  } else {
55
51
  return <LargeHeader />;
56
52
  }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import ActiveModalCountContext from "./activeModalCountContext";
26
+ import React, { FC, useCallback, useState } from "react";
27
+
28
+ /**
29
+ * A simple counter that allows developers to keep track of how many modals are currently open.
30
+ *
31
+ * A default provider instance wraps the SCM-Manager so there is no need for plugins to use this component.
32
+ *
33
+ * Required by {@link useActiveModals}.
34
+ */
35
+ const ActiveModalCountContextProvider: FC = ({ children }) => {
36
+ const [activeModalCount, setActiveModalCount] = useState(0);
37
+ const incrementModalCount = useCallback(() => setActiveModalCount((prev) => prev + 1), []);
38
+ const decrementModalCount = useCallback(() => setActiveModalCount((prev) => prev - 1), []);
39
+
40
+ return (
41
+ <ActiveModalCountContext.Provider
42
+ value={{ value: activeModalCount, increment: incrementModalCount, decrement: decrementModalCount }}
43
+ >
44
+ {children}
45
+ </ActiveModalCountContext.Provider>
46
+ );
47
+ };
48
+
49
+ export default ActiveModalCountContextProvider;
@@ -26,6 +26,7 @@ import { storiesOf } from "@storybook/react";
26
26
  import { MemoryRouter } from "react-router-dom";
27
27
  import * as React from "react";
28
28
  import ConfirmAlert, { confirmAlert } from "./ConfirmAlert";
29
+ import ActiveModalCountContext from "./activeModalCountContext";
29
30
 
30
31
  const body =
31
32
  "Mind-paralyzing change needed improbability vortex machine sorts sought same theory upending job just allows\n " +
@@ -37,27 +38,36 @@ const buttons = [
37
38
  {
38
39
  className: "is-outlined",
39
40
  label: "Cancel",
40
- onClick: () => null
41
+ onClick: () => null,
41
42
  },
42
43
  {
43
- label: "Submit"
44
- }
44
+ label: "Submit",
45
+ },
45
46
  ];
46
47
 
47
48
  const buttonsWithAutofocus = [
48
49
  {
49
50
  label: "Cancel",
50
- onClick: () => null
51
+ onClick: () => null,
51
52
  },
52
53
  {
53
54
  className: "is-info",
54
55
  label: "I should be focused",
55
- autofocus: true
56
- }
56
+ autofocus: true,
57
+ },
57
58
  ];
58
59
 
60
+ const doNothing = () => {
61
+ // Do nothing
62
+ };
63
+
59
64
  storiesOf("Modal/ConfirmAlert", module)
60
- .addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
65
+ .addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
66
+ .addDecorator((story) => (
67
+ <ActiveModalCountContext.Provider value={{ value: 0, increment: doNothing, decrement: doNothing }}>
68
+ {story()}
69
+ </ActiveModalCountContext.Provider>
70
+ ))
61
71
  .add("Default", () => <ConfirmAlert message={body} title={"Are you sure about that?"} buttons={buttons} />)
62
72
  .add("WithButton", () => {
63
73
  const buttonClick = () => {
@@ -34,6 +34,7 @@ import { Button, ButtonGroup } from "../buttons";
34
34
  import Notification from "../Notification";
35
35
  import { Autocomplete } from "../index";
36
36
  import { SelectValue } from "@scm-manager/ui-types";
37
+ import ActiveModalCountContext from "./activeModalCountContext";
37
38
 
38
39
  const TopAndBottomMargin = styled.div`
39
40
  margin: 0.75rem 0; // only for aesthetic reasons
@@ -75,20 +76,25 @@ const withFormElementsFooter = (
75
76
  );
76
77
 
77
78
  const loadSuggestions: (p: string) => Promise<SelectValue[]> = () =>
78
- new Promise(resolve => {
79
+ new Promise((resolve) => {
79
80
  setTimeout(() => {
80
81
  resolve([
81
82
  { value: { id: "trillian", displayName: "Tricia McMillan" }, label: "Tricia McMillan" },
82
83
  { value: { id: "zaphod", displayName: "Zaphod Beeblebrox" }, label: "Zaphod Beeblebrox" },
83
84
  { value: { id: "ford", displayName: "Ford Prefect" }, label: "Ford Prefect" },
84
85
  { value: { id: "dent", displayName: "Arthur Dent" }, label: "Arthur Dent" },
85
- { value: { id: "marvin", displayName: "Marvin" }, label: "Marvin the Paranoid Android " }
86
+ { value: { id: "marvin", displayName: "Marvin" }, label: "Marvin the Paranoid Android " },
86
87
  ]);
87
88
  });
88
89
  });
89
90
 
90
91
  storiesOf("Modal/Modal", module)
91
- .addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
92
+ .addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
93
+ .addDecorator((story) => (
94
+ <ActiveModalCountContext.Provider value={{ value: 0, increment: doNothing, decrement: doNothing }}>
95
+ {story()}
96
+ </ActiveModalCountContext.Provider>
97
+ ))
92
98
  .add("Default", () => (
93
99
  <NonCloseableModal>
94
100
  <p>{text}</p>
@@ -26,6 +26,7 @@ import classNames from "classnames";
26
26
  import styled from "styled-components";
27
27
  import { Dialog } from "@headlessui/react";
28
28
  import { devices } from "../devices";
29
+ import useRegisterModal from "./useRegisterModal";
29
30
 
30
31
  type ModalSize = "S" | "M" | "L";
31
32
 
@@ -67,6 +68,7 @@ export const Modal: FC<Props> = ({
67
68
  initialFocusRef,
68
69
  overflowVisible
69
70
  }) => {
71
+ useRegisterModal(active);
70
72
  const closeButtonRef = useRef<HTMLButtonElement | null>(null);
71
73
  let showFooter = null;
72
74
 
@@ -0,0 +1,29 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import React from "react";
26
+
27
+ export type ModalStateContextType = { value: number; increment: () => void; decrement: () => void };
28
+
29
+ export default React.createContext<ModalStateContextType>({} as ModalStateContextType);
@@ -27,3 +27,5 @@
27
27
  export { default as ConfirmAlert, confirmAlert } from "./ConfirmAlert";
28
28
  export { default as Modal } from "./Modal";
29
29
  export { default as FullscreenModal } from "./FullscreenModal";
30
+ export { default as ActiveModalCountContextProvider } from "./ActiveModalCountContextProvider";
31
+ export { default as useActiveModals } from "./useActiveModals";
@@ -0,0 +1,36 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { useContext } from "react";
26
+ import ActiveModalCountContext from "./activeModalCountContext";
27
+
28
+ /**
29
+ * @returns Whether any modals are currently open
30
+ */
31
+ const useActiveModals = () => {
32
+ const { value } = useContext(ActiveModalCountContext);
33
+ return value > 0;
34
+ };
35
+
36
+ export default useActiveModals;
@@ -0,0 +1,88 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { renderHook } from "@testing-library/react-hooks";
26
+ import React, { FC } from "react";
27
+ import ActiveModalCountContext, { ModalStateContextType } from "./activeModalCountContext";
28
+ import useRegisterModal from "./useRegisterModal";
29
+
30
+ const createWrapper =
31
+ (context: ModalStateContextType): FC =>
32
+ ({ children }) => {
33
+ return <ActiveModalCountContext.Provider value={context}>{children}</ActiveModalCountContext.Provider>;
34
+ };
35
+
36
+ describe("useRegisterModal", () => {
37
+ it("should increment and not decrement on active registration", () => {
38
+ const increment = jest.fn();
39
+ const decrement = jest.fn();
40
+
41
+ renderHook(() => useRegisterModal(true), {
42
+ wrapper: createWrapper({ value: 0, increment, decrement }),
43
+ });
44
+
45
+ expect(decrement).not.toHaveBeenCalled();
46
+ expect(increment).toHaveBeenCalled();
47
+ });
48
+
49
+ it("should not decrement on inactive registration", () => {
50
+ const increment = jest.fn();
51
+ const decrement = jest.fn();
52
+
53
+ renderHook(() => useRegisterModal(false), {
54
+ wrapper: createWrapper({ value: 0, increment, decrement }),
55
+ });
56
+
57
+ expect(decrement).not.toHaveBeenCalled();
58
+ expect(increment).not.toHaveBeenCalled();
59
+ });
60
+
61
+ it("should not decrement on inactive de-registration", () => {
62
+ const increment = jest.fn();
63
+ const decrement = jest.fn();
64
+
65
+ const result = renderHook(() => useRegisterModal(false), {
66
+ wrapper: createWrapper({ value: 0, increment, decrement }),
67
+ });
68
+
69
+ result.unmount();
70
+
71
+ expect(decrement).not.toHaveBeenCalled();
72
+ expect(increment).not.toHaveBeenCalled();
73
+ });
74
+
75
+ it("should decrement on active de-registration", () => {
76
+ const increment = jest.fn();
77
+ const decrement = jest.fn();
78
+
79
+ const result = renderHook(() => useRegisterModal(false, true), {
80
+ wrapper: createWrapper({ value: 0, increment, decrement }),
81
+ });
82
+
83
+ result.unmount();
84
+
85
+ expect(decrement).toHaveBeenCalled();
86
+ expect(increment).not.toHaveBeenCalled();
87
+ });
88
+ });
@@ -0,0 +1,53 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2020-present Cloudogu GmbH and Contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { useContext, useEffect, useRef } from "react";
26
+ import ActiveModalCount from "./activeModalCountContext";
27
+
28
+ /**
29
+ * Should not yet be part of the public API, as it is exclusively used by the {@link Modal} component.
30
+ *
31
+ * @param active Whether the modal is currently open
32
+ * @param initialValue DO NOT USE - Used only for testing purposes
33
+ */
34
+ export default function useRegisterModal(active: boolean, initialValue: boolean | null = null) {
35
+ const { increment, decrement } = useContext(ActiveModalCount);
36
+ const previousActiveState = useRef<boolean | null>(initialValue);
37
+ useEffect(() => {
38
+ if (active) {
39
+ previousActiveState.current = true;
40
+ increment();
41
+ } else {
42
+ if (previousActiveState.current !== null) {
43
+ decrement();
44
+ }
45
+ previousActiveState.current = false;
46
+ }
47
+ return () => {
48
+ if (previousActiveState.current) {
49
+ decrement();
50
+ }
51
+ };
52
+ }, [active, decrement, increment]);
53
+ }
@@ -40,7 +40,7 @@ type CollapsedProps = {
40
40
  const SectionContainer = styled.aside`
41
41
  position: sticky;
42
42
  position: -webkit-sticky; /* Safari */
43
- top: 2rem;
43
+ top: 5rem;
44
44
  width: 100%;
45
45
 
46
46
  @media (max-height: 900px) {