@scm-manager/ui-core 3.6.1 → 3.7.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.
@@ -22,7 +22,6 @@ const ReactDOM = require("react-dom");
22
22
 
23
23
  const root = path.resolve("..");
24
24
 
25
-
26
25
  const themedir = path.join(root, "ui-styles", "src");
27
26
 
28
27
  ReactDOM.createPortal = (node) => node;
@@ -46,7 +45,7 @@ module.exports = {
46
45
  "@storybook/addon-essentials",
47
46
  "@storybook/addon-interactions",
48
47
  "@storybook/addon-a11y",
49
- "storybook-addon-pseudo-states"
48
+ "storybook-addon-pseudo-states",
50
49
  ],
51
50
  framework: "@storybook/react",
52
51
  webpackFinal: async (config) => {
@@ -75,6 +74,9 @@ module.exports = {
75
74
  // to filter our themes from the output.
76
75
  config.plugins.push(new RemoveThemesPlugin());
77
76
 
77
+ // force node version of "decode-named-character-reference" instead of browser version which does not work in web worker
78
+ config.resolve.alias["decode-named-character-reference"] = require.resolve("decode-named-character-reference");
79
+
78
80
  // force cjs instead of esm
79
81
  // https://github.com/tannerlinsley/react-query/issues/3513
80
82
  config.resolve.alias["react-query/devtools"] = require.resolve("react-query/devtools");
@@ -17,9 +17,9 @@
17
17
  import i18next from "i18next";
18
18
  import { initReactI18next } from "react-i18next";
19
19
  import { withI18next } from "storybook-addon-i18next";
20
- import React, {useEffect} from "react";
20
+ import React, { useEffect } from "react";
21
21
  import withApiProvider from "./withApiProvider";
22
- import { withThemes } from 'storybook-addon-themes/react';
22
+ import { withThemes } from "storybook-addon-themes/react";
23
23
 
24
24
  let i18n = i18next;
25
25
 
@@ -27,7 +27,7 @@ let i18n = i18next;
27
27
  // and not for storyshots
28
28
  if (!process.env.JEST_WORKER_ID) {
29
29
  const Backend = require("i18next-fetch-backend");
30
- i18n = i18n.use(Backend.default);
30
+ i18n = i18n.use(Backend);
31
31
  }
32
32
 
33
33
  i18n.use(initReactI18next).init({
@@ -58,18 +58,18 @@ export const decorators = [
58
58
  },
59
59
  }),
60
60
  withApiProvider,
61
- withThemes
61
+ withThemes,
62
62
  ];
63
63
 
64
- const Decorator = ({children, themeName}) => {
64
+ const Decorator = ({ children, themeName }) => {
65
65
  useEffect(() => {
66
66
  const link = document.querySelector("#ui-theme");
67
67
  if (link && link["data-theme"] !== themeName) {
68
- link.href = `ui-theme-${themeName}.css`;
68
+ link.href = `/ui-theme-${themeName}.css`;
69
69
  link["data-theme"] = themeName;
70
70
  }
71
71
  }, [themeName]);
72
- return <>{children}</>
72
+ return <>{children}</>;
73
73
  };
74
74
 
75
75
  export const parameters = {
@@ -83,5 +83,5 @@ export const parameters = {
83
83
  { name: "highcontrast", color: "#050514" },
84
84
  { name: "dark", color: "#121212" },
85
85
  ],
86
- }
86
+ },
87
87
  };
@@ -1,2 +1,2 @@
1
- @scm-manager/ui-core:typecheck: cache hit, replaying output 408bc17fda972cfa
1
+ @scm-manager/ui-core:typecheck: cache hit, replaying output c71948b9c8540fde
2
2
  @scm-manager/ui-core:typecheck: $ tsc
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-manager/ui-core",
3
- "version": "3.6.1",
3
+ "version": "3.7.0",
4
4
  "main": "./src/index.ts",
5
5
  "license": "AGPL-3.0-only",
6
6
  "scripts": {
@@ -20,7 +20,7 @@
20
20
  "styled-components": "5"
21
21
  },
22
22
  "dependencies": {
23
- "@scm-manager/ui-api": "3.6.1",
23
+ "@scm-manager/ui-api": "3.7.0",
24
24
  "@radix-ui/react-radio-group": "^1.1.3",
25
25
  "@radix-ui/react-slot": "^1.0.1",
26
26
  "@radix-ui/react-visually-hidden": "^1.0.3",
@@ -37,7 +37,7 @@
37
37
  "@scm-manager/eslint-config": "^2.17.0",
38
38
  "@scm-manager/tsconfig": "^2.12.0",
39
39
  "@scm-manager/babel-preset": "^2.13.1",
40
- "@scm-manager/ui-types": "3.6.1",
40
+ "@scm-manager/ui-types": "3.7.0",
41
41
  "@types/mousetrap": "1.6.5",
42
42
  "@testing-library/react-hooks": "8.0.1",
43
43
  "@testing-library/react": "12.1.5",
@@ -29,6 +29,7 @@ export const ButtonVariants = {
29
29
  SECONDARY: "secondary",
30
30
  TERTIARY: "tertiary",
31
31
  SIGNAL: "signal",
32
+ INFO: "info",
32
33
  } as const;
33
34
 
34
35
  export const ButtonVariantList = Object.values(ButtonVariants);
@@ -41,6 +42,7 @@ const createButtonClasses = (variant?: ButtonVariant, isLoading?: boolean) =>
41
42
  "is-primary is-outlined": variant === "secondary",
42
43
  "is-primary is-inverted": variant === "tertiary",
43
44
  "is-warning": variant === "signal",
45
+ "is-info is-outlined": variant === "info",
44
46
  "is-loading": isLoading,
45
47
  });
46
48
 
@@ -14,5 +14,5 @@
14
14
  * along with this program. If not, see https://www.gnu.org/licenses/.
15
15
  */
16
16
 
17
- export { Button, LinkButton, ExternalLinkButton, ExternalLink, ButtonVariants } from "./Button";
17
+ export { Button, LinkButton, IconButton, ExternalLinkButton, ExternalLink, ButtonVariants } from "./Button";
18
18
  export { default as Icon } from "./Icon";
@@ -15,4 +15,5 @@
15
15
  */
16
16
 
17
17
  export { default as useAriaId } from "./useAriaId";
18
+ export { default as useDocumentTitle, useDocumentTitleForRepository } from "./useDocumentTitle";
18
19
  export { createAttributesForTesting, isDevBuild } from "./devbuild";
@@ -0,0 +1,48 @@
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 { renderHook } from "@testing-library/react-hooks";
18
+ import { Repository } from "@scm-manager/ui-types";
19
+ import { binder } from "@scm-manager/ui-extensions";
20
+ import useDocumentTitle, { useDocumentTitleForRepository } from "./useDocumentTitle";
21
+
22
+ describe("useDocumentTitle", () => {
23
+ it("should set document title", () => {
24
+ renderHook(() => useDocumentTitle("Part1", "Part2"));
25
+ expect(document.title).toBe("Part1 - Part2 - SCM-Manager");
26
+ });
27
+
28
+ it("should append title if extension is a string", () => {
29
+ binder.getExtension = () => ({ documentTitle: "myInstance" });
30
+ renderHook(() => useDocumentTitle("Part1", "Part2"));
31
+ expect(document.title).toBe("Part1 - Part2 - SCM-Manager (myInstance)");
32
+ });
33
+
34
+ it("should modify title if extension is a function", () => {
35
+ binder.getExtension = () => ({ documentTitle: (title: string) => `Modified: ${title}` });
36
+ renderHook(() => useDocumentTitle("Part1", "Part2"));
37
+ expect(document.title).toBe("Modified: Part1 - Part2 - SCM-Manager");
38
+ });
39
+ });
40
+
41
+ describe("useDocumentTitleForRepository", () => {
42
+ const repository: Repository = { namespace: "namespace", name: "name" } as Repository;
43
+
44
+ it("should set the document title for a repository", () => {
45
+ renderHook(() => useDocumentTitleForRepository(repository, "Part1", "Part2"));
46
+ expect(document.title).toBe("Part1 - Part2 - namespace/name - SCM-Manager");
47
+ });
48
+ });
@@ -0,0 +1,51 @@
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 { useEffect } from "react";
18
+ import { binder, extensionPoints } from "@scm-manager/ui-extensions";
19
+ import { Repository } from "@scm-manager/ui-types";
20
+
21
+ /**
22
+ * Hook to set the document title.
23
+ *
24
+ * @param titleParts - An array of title parts to be joined.
25
+ * Title parts should be sorted with the highest specificity first.
26
+ */
27
+ export default function useDocumentTitle(...titleParts: string[]) {
28
+ useEffect(() => {
29
+ const extension = binder.getExtension<extensionPoints.DocumentTitleExtensionPoint>("document.title");
30
+ let title = `${titleParts.join(" - ")} - SCM-Manager`;
31
+ if (extension) {
32
+ if (typeof extension.documentTitle === "string") {
33
+ title += ` (${extension.documentTitle})`;
34
+ } else if (typeof extension.documentTitle === "function") {
35
+ title = extension.documentTitle(title);
36
+ }
37
+ }
38
+ document.title = title;
39
+ }, [titleParts]);
40
+ }
41
+
42
+ /**
43
+ * Hook to set the document title for a repository.
44
+ *
45
+ * @param repository - The repository for which the title should be set.
46
+ * @param titleParts - An array of title parts to be joined.
47
+ * Title parts should be sorted with the highest specificity first.
48
+ */
49
+ export function useDocumentTitleForRepository(repository: Repository, ...titleParts: string[]) {
50
+ useDocumentTitle(...titleParts, repository.namespace + "/" + repository.name);
51
+ }
@@ -14,7 +14,7 @@
14
14
  * along with this program. If not, see https://www.gnu.org/licenses/.
15
15
  */
16
16
 
17
- import React, { HTMLAttributes, useEffect } from "react";
17
+ import React, { HTMLAttributes } from "react";
18
18
  import classNames from "classnames";
19
19
 
20
20
  type Props = {
@@ -24,16 +24,6 @@ type Props = {
24
24
  };
25
25
  const Title = React.forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement> & Props>(
26
26
  ({ title, customPageTitle, preventRefreshingPageTitle, children, className, ...props }, ref) => {
27
- useEffect(() => {
28
- if (!preventRefreshingPageTitle) {
29
- if (customPageTitle) {
30
- document.title = customPageTitle;
31
- } else if (title) {
32
- document.title = title;
33
- }
34
- }
35
- }, [title, preventRefreshingPageTitle, customPageTitle]);
36
-
37
27
  if (children || title) {
38
28
  return (
39
29
  <h1 className={classNames("title", className)} {...props} ref={ref}>