@scm-manager/ui-components 3.7.3 → 3.7.4-20250125-130119

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": "3.7.3",
3
+ "version": "3.7.4-20250125-130119",
4
4
  "description": "UI Components for SCM-Manager and its plugins",
5
5
  "main": "src/index.ts",
6
6
  "files": [
@@ -32,14 +32,14 @@
32
32
  "react-query": "^3.39.2"
33
33
  },
34
34
  "devDependencies": {
35
- "@scm-manager/ui-tests": "3.7.3",
36
- "@scm-manager/ui-types": "3.7.3",
35
+ "@scm-manager/ui-tests": "3.7.4-20250125-130119",
36
+ "@scm-manager/ui-types": "3.7.4-20250125-130119",
37
37
  "@types/fetch-mock": "^7.3.1",
38
38
  "@types/react-select": "^2.0.19",
39
39
  "@types/unist": "^2.0.3",
40
40
  "gitdiff-parser": "^0.2.2",
41
41
  "i18next-fetch-backend": "4",
42
- "webpack": "^5.72.0",
42
+ "webpack": "^5.76.0",
43
43
  "@storybook/addon-actions": "^6.5.10",
44
44
  "@storybook/addon-essentials": "^6.5.10",
45
45
  "@storybook/addon-interactions": "^6.5.10",
@@ -67,17 +67,17 @@
67
67
  "@scm-manager/jest-preset": "^2.14.1",
68
68
  "@scm-manager/prettier-config": "^2.12.0",
69
69
  "@scm-manager/tsconfig": "^2.13.0",
70
- "@scm-manager/ui-syntaxhighlighting": "3.7.3",
71
- "@scm-manager/ui-shortcuts": "3.7.3",
72
- "@scm-manager/ui-text": "3.7.3"
70
+ "@scm-manager/ui-syntaxhighlighting": "3.7.4-20250125-130119",
71
+ "@scm-manager/ui-shortcuts": "3.7.4-20250125-130119",
72
+ "@scm-manager/ui-text": "3.7.4-20250125-130119"
73
73
  },
74
74
  "dependencies": {
75
- "@scm-manager/ui-core": "3.7.3",
76
- "@scm-manager/ui-overlays": "3.7.3",
77
- "@scm-manager/ui-layout": "3.7.3",
78
- "@scm-manager/ui-buttons": "3.7.3",
79
- "@scm-manager/ui-api": "3.7.3",
80
- "@scm-manager/ui-extensions": "3.7.3",
75
+ "@scm-manager/ui-core": "3.7.4-20250125-130119",
76
+ "@scm-manager/ui-overlays": "3.7.4-20250125-130119",
77
+ "@scm-manager/ui-layout": "3.7.4-20250125-130119",
78
+ "@scm-manager/ui-buttons": "3.7.4-20250125-130119",
79
+ "@scm-manager/ui-api": "3.7.4-20250125-130119",
80
+ "@scm-manager/ui-extensions": "3.7.4-20250125-130119",
81
81
  "deepmerge": "^4.2.2",
82
82
  "hast-util-sanitize": "^3.0.2",
83
83
  "react-diff-view": "^2.4.10",
@@ -78158,11 +78158,18 @@ exports[`Storyshots Secondary Navigation Active when match 1`] = `
78158
78158
  <div>
78159
78159
  <button
78160
78160
  aria-label="secondaryNavigation.hideContent"
78161
- className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label is-clickable"
78161
+ className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label"
78162
78162
  collapsed={false}
78163
78163
  onClick={[Function]}
78164
78164
  type="button"
78165
78165
  >
78166
+ <i
78167
+ className="SecondaryNavigation__Icon-sc-8p1rgi-1 gqxbcY is-medium"
78168
+ >
78169
+ <i
78170
+ className="fas fa-caret-down"
78171
+ />
78172
+ </i>
78166
78173
  Hitchhiker
78167
78174
  </button>
78168
78175
  <ul
@@ -78215,7 +78222,7 @@ exports[`Storyshots Secondary Navigation Default 1`] = `
78215
78222
  <div>
78216
78223
  <button
78217
78224
  aria-label="secondaryNavigation.hideContent"
78218
- className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label is-clickable"
78225
+ className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label"
78219
78226
  collapsed={false}
78220
78227
  onClick={[Function]}
78221
78228
  type="button"
@@ -78278,7 +78285,7 @@ exports[`Storyshots Secondary Navigation Extension Point 1`] = `
78278
78285
  <div>
78279
78286
  <button
78280
78287
  aria-label="secondaryNavigation.hideContent"
78281
- className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label is-clickable"
78288
+ className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label"
78282
78289
  collapsed={false}
78283
78290
  onClick={[Function]}
78284
78291
  type="button"
@@ -78369,7 +78376,7 @@ exports[`Storyshots Secondary Navigation Sub Navigation 1`] = `
78369
78376
  <div>
78370
78377
  <button
78371
78378
  aria-label="secondaryNavigation.hideContent"
78372
- className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label is-clickable"
78379
+ className="button SecondaryNavigation__MenuButton-sc-8p1rgi-2 fkeiWf menu-label"
78373
78380
  collapsed={false}
78374
78381
  onClick={[Function]}
78375
78382
  type="button"
@@ -21,6 +21,7 @@ import { createAttributesForTesting } from "../devBuild";
21
21
  import useAutofocus from "./useAutofocus";
22
22
  import { createFormFieldWrapper, FieldProps, FieldType, isLegacy, isUsingRef } from "./FormFieldTypes";
23
23
  import { createA11yId } from "../createA11yId";
24
+ import FieldMessage from "@scm-manager/ui-core/src/base/forms/base/field-message/FieldMessage";
24
25
 
25
26
  type BaseProps = {
26
27
  label?: string;
@@ -40,6 +41,7 @@ type BaseProps = {
40
41
  defaultValue?: string | number;
41
42
  readOnly?: boolean;
42
43
  required?: boolean;
44
+ warning?: string;
43
45
  };
44
46
 
45
47
  export const InnerInputField: FC<FieldProps<BaseProps, HTMLInputElement, string>> = ({
@@ -60,6 +62,7 @@ export const InnerInputField: FC<FieldProps<BaseProps, HTMLInputElement, string>
60
62
  defaultValue,
61
63
  readOnly,
62
64
  required,
65
+ warning,
63
66
  ...props
64
67
  }) => {
65
68
  const field = useAutofocus<HTMLInputElement>(autofocus, props.innerRef);
@@ -123,6 +126,7 @@ export const InnerInputField: FC<FieldProps<BaseProps, HTMLInputElement, string>
123
126
  {...createAttributesForTesting(testId)}
124
127
  />
125
128
  </div>
129
+ {warning ? <FieldMessage variant="warning">{warning}</FieldMessage> : null}
126
130
  {helper}
127
131
  </fieldset>
128
132
  );
@@ -17,6 +17,7 @@
17
17
  import React, { FC } from "react";
18
18
  import styled from "styled-components";
19
19
  import { useSecondaryNavigation } from "../useSecondaryNavigation";
20
+ import { SecondaryNavigationProvider } from "../navigation/SecondaryNavigationContext";
20
21
 
21
22
  const SecondaryColumn = styled.div<{ collapsed: boolean }>`
22
23
  flex: 0 0 auto;
@@ -28,7 +29,7 @@ const SecondaryColumn = styled.div<{ collapsed: boolean }>`
28
29
  }
29
30
  `;
30
31
 
31
- const SecondaryNavigationColumn: FC = ({ children }) => {
32
+ const SecondaryNavigationColumnIntern: FC = ({ children }) => {
32
33
  const { collapsed } = useSecondaryNavigation();
33
34
 
34
35
  return (
@@ -38,4 +39,12 @@ const SecondaryNavigationColumn: FC = ({ children }) => {
38
39
  );
39
40
  };
40
41
 
42
+ const SecondaryNavigationColumn: FC = ({ children }) => {
43
+ return (
44
+ <SecondaryNavigationProvider>
45
+ <SecondaryNavigationColumnIntern>{children}</SecondaryNavigationColumnIntern>
46
+ </SecondaryNavigationProvider>
47
+ );
48
+ };
49
+
41
50
  export default SecondaryNavigationColumn;
@@ -14,11 +14,10 @@
14
14
  * along with this program. If not, see https://www.gnu.org/licenses/.
15
15
  */
16
16
 
17
- import React, { FC, useContext } from "react";
17
+ import React, { FC } from "react";
18
18
  import classNames from "classnames";
19
19
  import { useSecondaryNavigation } from "../useSecondaryNavigation";
20
20
  import ExternalLink from "./ExternalLink";
21
- import { SecondaryNavigationContext } from "./SecondaryNavigationContext";
22
21
 
23
22
  type Props = {
24
23
  to: string;
@@ -28,7 +27,6 @@ type Props = {
28
27
 
29
28
  const ExternalNavLink: FC<Props> = ({ to, icon, label }) => {
30
29
  const { collapsed } = useSecondaryNavigation();
31
- const isSecondaryNavigation = useContext(SecondaryNavigationContext);
32
30
 
33
31
  let showIcon;
34
32
  if (icon) {
@@ -43,7 +41,7 @@ const ExternalNavLink: FC<Props> = ({ to, icon, label }) => {
43
41
  <li title={collapsed ? label : undefined}>
44
42
  <ExternalLink to={to} className={collapsed ? "has-text-centered" : ""} aria-label={collapsed ? label : undefined}>
45
43
  {showIcon}
46
- {isSecondaryNavigation && collapsed ? null : label}
44
+ {collapsed ? null : label}
47
45
  </ExternalLink>
48
46
  </li>
49
47
  );
@@ -17,12 +17,11 @@
17
17
  import React, { FC, useContext, useEffect } from "react";
18
18
  import classNames from "classnames";
19
19
  import { Link } from "react-router-dom";
20
+ import { createAttributesForTesting } from "@scm-manager/ui-core";
20
21
  import { useSecondaryNavigation } from "../useSecondaryNavigation";
21
22
  import { RoutingProps } from "./RoutingProps";
22
- import useActiveMatch from "./useActiveMatch";
23
- import { createAttributesForTesting } from "@scm-manager/ui-core";
24
- import { SecondaryNavigationContext } from "./SecondaryNavigationContext";
25
23
  import { SubNavigationContext } from "./SubNavigationContext";
24
+ import useActiveMatch from "./useActiveMatch";
26
25
 
27
26
  type Props = RoutingProps & {
28
27
  label: string;
@@ -51,14 +50,13 @@ const NavLinkContent: FC<NavLinkContentProp> = ({ label, icon, collapsed }) => (
51
50
  const NavLink: FC<Props> = ({ to, activeWhenMatch, activeOnlyWhenExact, title, testId, children, ...contentProps }) => {
52
51
  const active = useActiveMatch({ to, activeWhenMatch, activeOnlyWhenExact });
53
52
  const { collapsed, setCollapsible } = useSecondaryNavigation();
54
- const isSecondaryNavigation = useContext(SecondaryNavigationContext);
55
53
  const isSubNavigation = useContext(SubNavigationContext);
56
54
 
57
55
  useEffect(() => {
58
- if (isSecondaryNavigation && active) {
56
+ if (active) {
59
57
  setCollapsible(!isSubNavigation);
60
58
  }
61
- }, [active, isSecondaryNavigation, isSubNavigation, setCollapsible]);
59
+ }, [active, isSubNavigation, setCollapsible]);
62
60
 
63
61
  return (
64
62
  <li title={collapsed ? title : undefined}>
@@ -69,11 +67,7 @@ const NavLink: FC<Props> = ({ to, activeWhenMatch, activeOnlyWhenExact, title, t
69
67
  aria-label={collapsed ? title : undefined}
70
68
  {...(active ? { "aria-current": "page" } : {})}
71
69
  >
72
- {children ? (
73
- children
74
- ) : (
75
- <NavLinkContent {...contentProps} collapsed={(isSecondaryNavigation && collapsed) ?? false} />
76
- )}
70
+ {children || <NavLinkContent {...contentProps} collapsed={collapsed} />}
77
71
  </Link>
78
72
  </li>
79
73
  );
@@ -16,12 +16,13 @@
16
16
 
17
17
  import { storiesOf } from "@storybook/react";
18
18
  import React, { ReactElement } from "react";
19
+ import { MemoryRouter } from "react-router-dom";
20
+ import styled from "styled-components";
21
+ import { Binder, ExtensionPoint, BinderContext } from "@scm-manager/ui-extensions";
22
+ import { SecondaryNavigationProvider } from "./SecondaryNavigationContext";
19
23
  import SecondaryNavigation from "./SecondaryNavigation";
20
24
  import SecondaryNavigationItem from "./SecondaryNavigationItem";
21
- import styled from "styled-components";
22
25
  import SubNavigation from "./SubNavigation";
23
- import { Binder, ExtensionPoint, BinderContext } from "@scm-manager/ui-extensions";
24
- import { MemoryRouter } from "react-router-dom";
25
26
 
26
27
  const Columns = styled.div`
27
28
  margin: 2rem;
@@ -46,7 +47,9 @@ const withRoute = (route: string) => {
46
47
  storiesOf("Secondary Navigation", module)
47
48
  .addDecorator((story) => (
48
49
  <Columns className="columns">
49
- <div className="column is-3">{story()}</div>
50
+ <div className="column is-3">
51
+ <SecondaryNavigationProvider>{story()}</SecondaryNavigationProvider>
52
+ </div>
50
53
  </Columns>
51
54
  ))
52
55
  .add("Default", () =>
@@ -16,10 +16,8 @@
16
16
 
17
17
  import React, { FC } from "react";
18
18
  import styled from "styled-components";
19
- import classNames from "classnames";
20
19
  import { useTranslation } from "react-i18next";
21
20
  import { useSecondaryNavigation } from "../useSecondaryNavigation";
22
- import { SecondaryNavigationContext } from "./SecondaryNavigationContext";
23
21
  import { Button } from "@scm-manager/ui-buttons";
24
22
 
25
23
  type Props = {
@@ -73,14 +71,9 @@ const SecondaryNavigation: FC<Props> = ({ label, children, collapsible = true })
73
71
  const menuAriaLabel = collapsed ? t("secondaryNavigation.showContent") : t("secondaryNavigation.hideContent");
74
72
 
75
73
  return (
76
- <SectionContainer className="menu" collapsed={collapsed ?? false}>
74
+ <SectionContainer className="menu" collapsed={collapsed}>
77
75
  <div>
78
- <MenuButton
79
- className={classNames("menu-label", { "is-clickable": true })}
80
- collapsed={collapsed}
81
- onClick={toggleCollapse}
82
- aria-label={menuAriaLabel}
83
- >
76
+ <MenuButton className="menu-label" collapsed={collapsed} onClick={toggleCollapse} aria-label={menuAriaLabel}>
84
77
  {isCollapsible ? (
85
78
  <Icon className="is-medium" collapsed={collapsed}>
86
79
  {arrowIcon}
@@ -88,9 +81,7 @@ const SecondaryNavigation: FC<Props> = ({ label, children, collapsible = true })
88
81
  ) : null}
89
82
  {collapsed ? "" : label}
90
83
  </MenuButton>
91
- <ul className="menu-list">
92
- <SecondaryNavigationContext.Provider value={true}>{children}</SecondaryNavigationContext.Provider>
93
- </ul>
84
+ <ul className="menu-list">{children}</ul>
94
85
  </div>
95
86
  </SectionContainer>
96
87
  );
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Copyright (c) 2020 - present Cloudogu GmbH
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify it under
5
+ * the terms of the GNU Affero General Public License as published by the Free
6
+ * Software Foundation, version 3.
7
+ *
8
+ * This program is distributed in the hope that it will be useful, but WITHOUT
9
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
+ * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
11
+ * details.
12
+ *
13
+ * You should have received a copy of the GNU Affero General Public License
14
+ * along with this program. If not, see https://www.gnu.org/licenses/.
15
+ */
16
+
17
+ import React, { ReactNode, useMemo, useState } from "react";
18
+
19
+ type SecondaryNavigationContextState = {
20
+ collapsible: boolean;
21
+ setCollapsible: (collapsed: boolean) => void;
22
+ };
23
+
24
+ const dummy: SecondaryNavigationContextState = {
25
+ collapsible: false,
26
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
27
+ setCollapsible: () => {},
28
+ };
29
+
30
+ export const SecondaryNavigationContext = React.createContext<SecondaryNavigationContextState>(dummy);
31
+
32
+ export const SecondaryNavigationProvider = ({ children }: { children: ReactNode }) => {
33
+ const [collapsible, setCollapsible] = useState(true);
34
+ const contextValue = useMemo(() => ({ collapsible, setCollapsible }), [collapsible, setCollapsible]);
35
+
36
+ return <SecondaryNavigationContext.Provider value={contextValue}>{children}</SecondaryNavigationContext.Provider>;
37
+ };
@@ -15,17 +15,14 @@
15
15
  */
16
16
 
17
17
  import { useLocalStorage } from "@scm-manager/ui-api";
18
- import { useCallback, useMemo } from "react";
18
+ import { useCallback, useContext } from "react";
19
+ import { SecondaryNavigationContext } from "./navigation/SecondaryNavigationContext";
19
20
 
20
21
  export const useSecondaryNavigation = (isNavigationCollapsible = true) => {
21
- const [isCollapsed, setCollapsed] = useLocalStorage<boolean>("secondaryNavigation.collapsed", false);
22
- const [isRouteCollapsible, setRouteCollapsible] = useLocalStorage<boolean>("secondaryNavigation.collapsible", true);
22
+ const { collapsible, setCollapsible } = useContext(SecondaryNavigationContext);
23
+ const [isCollapsed, setCollapsed] = useLocalStorage("secondaryNavigation.collapsed", false);
23
24
 
24
- const collapsible = useMemo(
25
- () => isRouteCollapsible && isNavigationCollapsible,
26
- [isNavigationCollapsible, isRouteCollapsible]
27
- );
28
- const collapsed = useMemo(() => collapsible && isCollapsed, [collapsible, isCollapsed]);
25
+ const collapsed = collapsible && isCollapsed;
29
26
 
30
27
  const toggleCollapse = useCallback(() => {
31
28
  if (collapsible) {
@@ -33,13 +30,10 @@ export const useSecondaryNavigation = (isNavigationCollapsible = true) => {
33
30
  }
34
31
  }, [collapsible, setCollapsed]);
35
32
 
36
- return useMemo(
37
- () => ({
38
- collapsed,
39
- collapsible,
40
- setCollapsible: setRouteCollapsible,
41
- toggleCollapse,
42
- }),
43
- [collapsed, collapsible, setRouteCollapsible, toggleCollapse]
44
- );
33
+ return {
34
+ collapsed,
35
+ collapsible,
36
+ setCollapsible,
37
+ toggleCollapse,
38
+ };
45
39
  };
@@ -1,19 +0,0 @@
1
- /*
2
- * Copyright (c) 2020 - present Cloudogu GmbH
3
- *
4
- * This program is free software: you can redistribute it and/or modify it under
5
- * the terms of the GNU Affero General Public License as published by the Free
6
- * Software Foundation, version 3.
7
- *
8
- * This program is distributed in the hope that it will be useful, but WITHOUT
9
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
- * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
11
- * details.
12
- *
13
- * You should have received a copy of the GNU Affero General Public License
14
- * along with this program. If not, see https://www.gnu.org/licenses/.
15
- */
16
-
17
- import React from "react";
18
-
19
- export const SecondaryNavigationContext = React.createContext(false);