@openmrs/esm-react-utils 3.4.1-pre.96 → 4.0.0-pre.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/.turbo/turbo-build.log +11 -11
- package/.turbo/turbo-lint.log +2 -0
- package/.turbo/turbo-test.log +45 -0
- package/dist/openmrs-esm-react-utils.js +1 -1
- package/dist/openmrs-esm-react-utils.js.map +1 -1
- package/jest.config.js +4 -0
- package/package.json +18 -18
- package/src/ConfigurableLink.test.tsx +6 -4
- package/src/ConfigurableLink.tsx +22 -13
- package/src/UserHasAccess.tsx +6 -3
- package/src/openmrsComponentDecorator.tsx +2 -1
- package/src/useLayoutType.ts +8 -2
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-react-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-pre.1",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "React utilities for OpenMRS.",
|
|
6
6
|
"browser": "dist/openmrs-esm-react-utils.js",
|
|
@@ -39,34 +39,34 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"lodash-es": "^4.17.21",
|
|
42
|
-
"single-spa-react": "^4.
|
|
42
|
+
"single-spa-react": "^4.6.1",
|
|
43
43
|
"swr": "^1.2.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@openmrs/esm-api": "
|
|
47
|
-
"@openmrs/esm-config": "
|
|
48
|
-
"@openmrs/esm-error-handling": "
|
|
49
|
-
"@openmrs/esm-extensions": "
|
|
50
|
-
"@openmrs/esm-globals": "
|
|
46
|
+
"@openmrs/esm-api": "4.x",
|
|
47
|
+
"@openmrs/esm-config": "4.x",
|
|
48
|
+
"@openmrs/esm-error-handling": "4.x",
|
|
49
|
+
"@openmrs/esm-extensions": "4.x",
|
|
50
|
+
"@openmrs/esm-globals": "4.x",
|
|
51
51
|
"dayjs": "1.x",
|
|
52
52
|
"i18next": "19.x",
|
|
53
|
-
"react": "
|
|
54
|
-
"react-dom": "
|
|
53
|
+
"react": "18.x",
|
|
54
|
+
"react-dom": "18.x",
|
|
55
55
|
"react-i18next": "11.x"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@openmrs/esm-api": "^
|
|
59
|
-
"@openmrs/esm-config": "^
|
|
60
|
-
"@openmrs/esm-error-handling": "^
|
|
61
|
-
"@openmrs/esm-extensions": "^
|
|
62
|
-
"@openmrs/esm-globals": "^
|
|
58
|
+
"@openmrs/esm-api": "^4.0.0-pre.1",
|
|
59
|
+
"@openmrs/esm-config": "^4.0.0-pre.1",
|
|
60
|
+
"@openmrs/esm-error-handling": "^4.0.0-pre.1",
|
|
61
|
+
"@openmrs/esm-extensions": "^4.0.0-pre.1",
|
|
62
|
+
"@openmrs/esm-globals": "^4.0.0-pre.1",
|
|
63
63
|
"dayjs": "^1.10.8",
|
|
64
64
|
"i18next": "^19.6.0",
|
|
65
|
-
"react": "^
|
|
66
|
-
"react-dom": "^
|
|
67
|
-
"react-i18next": "^11.
|
|
65
|
+
"react": "^18.1.0",
|
|
66
|
+
"react-dom": "^18.1.0",
|
|
67
|
+
"react-i18next": "^11.16.9",
|
|
68
68
|
"rxjs": "^6.5.3",
|
|
69
69
|
"unistore": "^3.5.2"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "9f58b801f07526083a9edc1cc5a1e58660d71eb0"
|
|
72
72
|
}
|
|
@@ -5,6 +5,8 @@ import { navigate, interpolateUrl } from "@openmrs/esm-config";
|
|
|
5
5
|
import userEvent from "@testing-library/user-event";
|
|
6
6
|
import { ConfigurableLink } from "./ConfigurableLink";
|
|
7
7
|
|
|
8
|
+
jest.mock("single-spa");
|
|
9
|
+
|
|
8
10
|
jest.mock("@openmrs/esm-config");
|
|
9
11
|
const mockNavigate = navigate as jest.Mock;
|
|
10
12
|
|
|
@@ -34,18 +36,18 @@ describe(`ConfigurableLink`, () => {
|
|
|
34
36
|
expect(link.closest("a")).toHaveAttribute("href", "/openmrs/spa/home");
|
|
35
37
|
});
|
|
36
38
|
|
|
37
|
-
it(`calls navigate on normal click but not
|
|
39
|
+
it(`calls navigate on normal click but not special clicks`, async () => {
|
|
38
40
|
const link = screen.getByRole("link", { name: /spa home/i });
|
|
39
|
-
userEvent.
|
|
41
|
+
await userEvent.pointer({ target: link, keys: "[MouseRight]" });
|
|
40
42
|
expect(navigate).not.toHaveBeenCalled();
|
|
41
|
-
userEvent.click(link);
|
|
43
|
+
await userEvent.click(link);
|
|
42
44
|
expect(navigate).toHaveBeenCalledWith({ to: path });
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
it(`calls navigate on enter`, async () => {
|
|
46
48
|
expect(navigate).not.toHaveBeenCalled();
|
|
47
49
|
const link = screen.getByRole("link", { name: /spa home/i });
|
|
48
|
-
userEvent.type(link, "{enter}");
|
|
50
|
+
await userEvent.type(link, "{enter}");
|
|
49
51
|
expect(navigate).toHaveBeenCalledWith({ to: path });
|
|
50
52
|
});
|
|
51
53
|
});
|
package/src/ConfigurableLink.tsx
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/** @module @category Navigation */
|
|
2
2
|
import React, { MouseEvent, AnchorHTMLAttributes } from "react";
|
|
3
|
-
import { navigate, interpolateUrl } from "@openmrs/esm-config";
|
|
3
|
+
import { navigate, interpolateUrl, TemplateParams } from "@openmrs/esm-config";
|
|
4
4
|
|
|
5
|
-
function handleClick(
|
|
5
|
+
function handleClick(
|
|
6
|
+
event: MouseEvent,
|
|
7
|
+
to: string,
|
|
8
|
+
templateParams?: TemplateParams
|
|
9
|
+
) {
|
|
6
10
|
if (
|
|
7
11
|
!event.metaKey &&
|
|
8
12
|
!event.ctrlKey &&
|
|
@@ -10,7 +14,7 @@ function handleClick(event: MouseEvent, to: string) {
|
|
|
10
14
|
event.button == 0
|
|
11
15
|
) {
|
|
12
16
|
event.preventDefault();
|
|
13
|
-
navigate({ to });
|
|
17
|
+
navigate({ to, templateParams });
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -20,25 +24,30 @@ function handleClick(event: MouseEvent, to: string) {
|
|
|
20
24
|
export interface ConfigurableLinkProps
|
|
21
25
|
extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
22
26
|
to: string;
|
|
27
|
+
templateParams?: TemplateParams;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
31
|
* A React link component which calls [[navigate]] when clicked
|
|
27
32
|
*
|
|
28
33
|
* @param to The target path or URL. Supports interpolation. See [[navigate]]
|
|
34
|
+
* @param urlParams: A dictionary of values to interpolate into the URL, in addition to the default keys `openmrsBase` and `openmrsSpaBase`.
|
|
29
35
|
* @param children Inline elements within the link
|
|
30
36
|
* @param otherProps Any other valid props for an <a> tag except `href` and `onClick`
|
|
31
37
|
*/
|
|
32
|
-
export
|
|
38
|
+
export function ConfigurableLink({
|
|
33
39
|
to,
|
|
40
|
+
templateParams,
|
|
34
41
|
children,
|
|
35
42
|
...otherProps
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
}: ConfigurableLinkProps) {
|
|
44
|
+
return (
|
|
45
|
+
<a
|
|
46
|
+
onClick={(event) => handleClick(event, to, templateParams)}
|
|
47
|
+
href={interpolateUrl(to, templateParams)}
|
|
48
|
+
{...otherProps}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</a>
|
|
52
|
+
);
|
|
53
|
+
}
|
package/src/UserHasAccess.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
+
import { getCurrentUser, LoggedInUser, userHasAccess } from "@openmrs/esm-api";
|
|
2
3
|
import React, { useEffect, useState } from "react";
|
|
3
|
-
import { getCurrentUser, userHasAccess, LoggedInUser } from "@openmrs/esm-api";
|
|
4
4
|
|
|
5
5
|
export interface UserHasAccessProps {
|
|
6
6
|
privilege: string;
|
|
7
|
+
fallback?: React.ReactNode;
|
|
8
|
+
children?: React.ReactNode;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
export const UserHasAccess: React.FC<UserHasAccessProps> = ({
|
|
10
12
|
privilege,
|
|
13
|
+
fallback,
|
|
11
14
|
children,
|
|
12
15
|
}) => {
|
|
13
16
|
const [user, setUser] = useState<LoggedInUser | null>(null);
|
|
@@ -21,7 +24,7 @@ export const UserHasAccess: React.FC<UserHasAccessProps> = ({
|
|
|
21
24
|
|
|
22
25
|
if (user && userHasAccess(privilege, user)) {
|
|
23
26
|
return <>{children}</>;
|
|
27
|
+
} else {
|
|
28
|
+
return fallback ? <>{fallback}</> : null;
|
|
24
29
|
}
|
|
25
|
-
|
|
26
|
-
return null;
|
|
27
30
|
};
|
|
@@ -18,6 +18,7 @@ const defaultOpts = {
|
|
|
18
18
|
interface I18nextLoadNamespaceProps {
|
|
19
19
|
forceUpdate(): void;
|
|
20
20
|
ns: string;
|
|
21
|
+
children?: React.ReactNode;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const I18nextLoadNamespace: React.FC<I18nextLoadNamespaceProps> = (props) => {
|
|
@@ -80,7 +81,7 @@ export function openmrsComponentDecorator(userOpts: ComponentDecoratorOptions) {
|
|
|
80
81
|
const opts = Object.assign({}, defaultOpts, userOpts);
|
|
81
82
|
|
|
82
83
|
return function decorateComponent(
|
|
83
|
-
Comp: React.ComponentType
|
|
84
|
+
Comp: React.ComponentType<any>
|
|
84
85
|
): React.ComponentType<any> {
|
|
85
86
|
return class OpenmrsReactComponent extends React.Component<
|
|
86
87
|
OpenmrsReactComponentProps,
|
package/src/useLayoutType.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @module @category UI */
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
|
|
4
|
-
export type LayoutType = "tablet" | "
|
|
4
|
+
export type LayoutType = "phone" | "tablet" | "small-desktop" | "large-desktop";
|
|
5
5
|
|
|
6
6
|
function getLayout() {
|
|
7
7
|
let layout: LayoutType = "tablet";
|
|
@@ -11,8 +11,11 @@ function getLayout() {
|
|
|
11
11
|
case "omrs-breakpoint-lt-tablet":
|
|
12
12
|
layout = "phone";
|
|
13
13
|
break;
|
|
14
|
+
case "omrs-breakpoint-gt-small-desktop":
|
|
15
|
+
layout = "large-desktop";
|
|
16
|
+
break;
|
|
14
17
|
case "omrs-breakpoint-gt-tablet":
|
|
15
|
-
layout = "desktop";
|
|
18
|
+
layout = "small-desktop";
|
|
16
19
|
break;
|
|
17
20
|
}
|
|
18
21
|
});
|
|
@@ -33,3 +36,6 @@ export function useLayoutType() {
|
|
|
33
36
|
|
|
34
37
|
return type;
|
|
35
38
|
}
|
|
39
|
+
|
|
40
|
+
export const isDesktop = (layout: LayoutType) =>
|
|
41
|
+
layout === "small-desktop" || layout === "large-desktop";
|