@openmrs/esm-react-utils 5.3.3-pre.1237 → 5.3.3-pre.1247
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 +2 -2
- package/__mocks__/openmrs-esm-state.mock.ts +8 -20
- package/dist/openmrs-esm-react-utils.js.map +1 -1
- package/jest.config.js +9 -11
- package/package.json +7 -7
- package/src/ComponentContext.ts +2 -2
- package/src/ConfigurableLink.test.tsx +19 -23
- package/src/ConfigurableLink.tsx +5 -19
- package/src/Extension.tsx +36 -76
- package/src/ExtensionSlot.tsx +15 -24
- package/src/UserHasAccess.tsx +3 -7
- package/src/extensions.test.tsx +100 -179
- package/src/getLifecycle.ts +8 -18
- package/src/index.ts +31 -31
- package/src/openmrsComponentDecorator.test.tsx +12 -12
- package/src/openmrsComponentDecorator.tsx +12 -26
- package/src/public.ts +27 -27
- package/src/setup-tests.js +4 -4
- package/src/useAbortController.test.tsx +8 -8
- package/src/useAbortController.ts +1 -1
- package/src/useAssignedExtensionIds.ts +4 -5
- package/src/useAssignedExtensions.ts +3 -7
- package/src/useBodyScrollLock.ts +2 -2
- package/src/useConfig.test.tsx +96 -112
- package/src/useConfig.ts +15 -43
- package/src/useConnectedExtensions.ts +8 -17
- package/src/useConnectivity.ts +3 -6
- package/src/useDebounce.ts +1 -1
- package/src/useExtensionInternalStore.ts +3 -8
- package/src/useExtensionSlot.ts +5 -7
- package/src/useExtensionSlotMeta.ts +5 -11
- package/src/useExtensionStore.ts +3 -5
- package/src/useFeatureFlag.ts +4 -4
- package/src/useForceUpdate.ts +1 -1
- package/src/useLayoutType.ts +12 -13
- package/src/useLocations.tsx +3 -3
- package/src/useOnClickOutside.test.tsx +10 -10
- package/src/useOnClickOutside.ts +2 -5
- package/src/useOpenmrsSWR.ts +9 -9
- package/src/usePagination.ts +6 -18
- package/src/usePatient.ts +9 -13
- package/src/useSession.test.tsx +35 -43
- package/src/useSession.ts +9 -13
- package/src/useStore.test.ts +11 -13
- package/src/useStore.ts +10 -31
- package/src/useVisit.ts +14 -37
- package/src/useVisitTypes.ts +3 -3
- package/webpack.config.js +14 -14
package/jest.config.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
transform: {
|
|
3
|
-
|
|
3
|
+
'^.+\\.(j|t)sx?$': ['@swc/jest'],
|
|
4
4
|
},
|
|
5
|
-
setupFilesAfterEnv: [
|
|
5
|
+
setupFilesAfterEnv: ['<rootDir>/src/setup-tests.js'],
|
|
6
6
|
moduleNameMapper: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"<rootDir>/__mocks__/openmrs-esm-styleguide.mock.tsx",
|
|
13
|
-
dexie: require.resolve("dexie"),
|
|
7
|
+
'^lodash-es/(.*)$': 'lodash/$1',
|
|
8
|
+
'@openmrs/esm-error-handling': '<rootDir>/__mocks__/openmrs-esm-error-handling.mock.ts',
|
|
9
|
+
'@openmrs/esm-state': '<rootDir>/__mocks__/openmrs-esm-state.mock.ts',
|
|
10
|
+
'@openmrs/esm-styleguide': '<rootDir>/__mocks__/openmrs-esm-styleguide.mock.tsx',
|
|
11
|
+
dexie: require.resolve('dexie'),
|
|
14
12
|
},
|
|
15
|
-
testEnvironment:
|
|
13
|
+
testEnvironment: 'jsdom',
|
|
16
14
|
testEnvironmentOptions: {
|
|
17
|
-
url:
|
|
15
|
+
url: 'http://localhost/',
|
|
18
16
|
},
|
|
19
17
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-react-utils",
|
|
3
|
-
"version": "5.3.3-pre.
|
|
3
|
+
"version": "5.3.3-pre.1247",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "React utilities for OpenMRS.",
|
|
6
6
|
"browser": "dist/openmrs-esm-react-utils.js",
|
|
@@ -57,12 +57,12 @@
|
|
|
57
57
|
"swr": "2.x"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@openmrs/esm-api": "5.3.3-pre.
|
|
61
|
-
"@openmrs/esm-config": "5.3.3-pre.
|
|
62
|
-
"@openmrs/esm-error-handling": "5.3.3-pre.
|
|
63
|
-
"@openmrs/esm-extensions": "5.3.3-pre.
|
|
64
|
-
"@openmrs/esm-feature-flags": "5.3.3-pre.
|
|
65
|
-
"@openmrs/esm-globals": "5.3.3-pre.
|
|
60
|
+
"@openmrs/esm-api": "5.3.3-pre.1247",
|
|
61
|
+
"@openmrs/esm-config": "5.3.3-pre.1247",
|
|
62
|
+
"@openmrs/esm-error-handling": "5.3.3-pre.1247",
|
|
63
|
+
"@openmrs/esm-extensions": "5.3.3-pre.1247",
|
|
64
|
+
"@openmrs/esm-feature-flags": "5.3.3-pre.1247",
|
|
65
|
+
"@openmrs/esm-globals": "5.3.3-pre.1247",
|
|
66
66
|
"dayjs": "^1.10.8",
|
|
67
67
|
"i18next": "^21.10.0",
|
|
68
68
|
"react": "^18.1.0",
|
package/src/ComponentContext.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
export interface ExtensionData {
|
|
4
4
|
extensionSlotName: string;
|
|
@@ -15,5 +15,5 @@ export interface ComponentConfig {
|
|
|
15
15
|
* Available to all components. Provided by `openmrsComponentDecorator`.
|
|
16
16
|
*/
|
|
17
17
|
export const ComponentContext = React.createContext<ComponentConfig>({
|
|
18
|
-
moduleName:
|
|
18
|
+
moduleName: '',
|
|
19
19
|
});
|
|
@@ -1,46 +1,42 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import
|
|
3
|
-
import { render, screen } from
|
|
4
|
-
import userEvent from
|
|
5
|
-
import { navigate, interpolateUrl } from
|
|
6
|
-
import { ConfigurableLink } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import userEvent from '@testing-library/user-event';
|
|
5
|
+
import { navigate, interpolateUrl } from '@openmrs/esm-config';
|
|
6
|
+
import { ConfigurableLink } from './ConfigurableLink';
|
|
7
7
|
|
|
8
|
-
jest.mock(
|
|
8
|
+
jest.mock('single-spa');
|
|
9
9
|
|
|
10
|
-
jest.mock(
|
|
10
|
+
jest.mock('@openmrs/esm-config');
|
|
11
11
|
const mockNavigate = navigate as jest.Mock;
|
|
12
12
|
|
|
13
|
-
const realInterpolate = jest.requireActual(
|
|
14
|
-
"@openmrs/esm-config"
|
|
15
|
-
).interpolateUrl;
|
|
13
|
+
const realInterpolate = jest.requireActual('@openmrs/esm-config').interpolateUrl;
|
|
16
14
|
|
|
17
|
-
(interpolateUrl as jest.Mock).mockImplementation((...args) =>
|
|
18
|
-
realInterpolate(...args)
|
|
19
|
-
);
|
|
15
|
+
(interpolateUrl as jest.Mock).mockImplementation((...args) => realInterpolate(...args));
|
|
20
16
|
|
|
21
17
|
describe(`ConfigurableLink`, () => {
|
|
22
|
-
const path =
|
|
18
|
+
const path = '${openmrsSpaBase}/home';
|
|
23
19
|
beforeEach(() => {
|
|
24
20
|
mockNavigate.mockClear();
|
|
25
21
|
render(
|
|
26
22
|
<ConfigurableLink to={path} className="fancy-link">
|
|
27
23
|
SPA Home
|
|
28
|
-
</ConfigurableLink
|
|
24
|
+
</ConfigurableLink>,
|
|
29
25
|
);
|
|
30
26
|
});
|
|
31
27
|
|
|
32
28
|
it(`interpolates the link`, async () => {
|
|
33
|
-
const link = screen.getByRole(
|
|
29
|
+
const link = screen.getByRole('link', { name: /spa home/i });
|
|
34
30
|
expect(link).toBeTruthy();
|
|
35
|
-
expect(link.closest(
|
|
36
|
-
expect(link.closest(
|
|
31
|
+
expect(link.closest('a')).toHaveClass('fancy-link');
|
|
32
|
+
expect(link.closest('a')).toHaveAttribute('href', '/openmrs/spa/home');
|
|
37
33
|
});
|
|
38
34
|
|
|
39
35
|
it(`calls navigate on normal click but not special clicks`, async () => {
|
|
40
36
|
const user = userEvent.setup();
|
|
41
37
|
|
|
42
|
-
const link = screen.getByRole(
|
|
43
|
-
await user.pointer({ target: link, keys:
|
|
38
|
+
const link = screen.getByRole('link', { name: /spa home/i });
|
|
39
|
+
await user.pointer({ target: link, keys: '[MouseRight]' });
|
|
44
40
|
expect(navigate).not.toHaveBeenCalled();
|
|
45
41
|
await user.click(link);
|
|
46
42
|
expect(navigate).toHaveBeenCalledWith({ to: path });
|
|
@@ -50,8 +46,8 @@ describe(`ConfigurableLink`, () => {
|
|
|
50
46
|
const user = userEvent.setup();
|
|
51
47
|
|
|
52
48
|
expect(navigate).not.toHaveBeenCalled();
|
|
53
|
-
const link = screen.getByRole(
|
|
54
|
-
await user.type(link,
|
|
49
|
+
const link = screen.getByRole('link', { name: /spa home/i });
|
|
50
|
+
await user.type(link, '{enter}');
|
|
55
51
|
expect(navigate).toHaveBeenCalledWith({ to: path });
|
|
56
52
|
});
|
|
57
53
|
});
|
package/src/ConfigurableLink.tsx
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
/** @module @category Navigation */
|
|
2
|
-
import React, {
|
|
3
|
-
|
|
4
|
-
type AnchorHTMLAttributes,
|
|
5
|
-
type PropsWithChildren,
|
|
6
|
-
} from "react";
|
|
7
|
-
import { navigate, interpolateUrl, TemplateParams } from "@openmrs/esm-config";
|
|
2
|
+
import React, { type MouseEvent, type AnchorHTMLAttributes, type PropsWithChildren } from 'react';
|
|
3
|
+
import { navigate, interpolateUrl, TemplateParams } from '@openmrs/esm-config';
|
|
8
4
|
|
|
9
|
-
function handleClick(
|
|
10
|
-
event
|
|
11
|
-
to: string,
|
|
12
|
-
templateParams?: TemplateParams
|
|
13
|
-
) {
|
|
14
|
-
if (
|
|
15
|
-
!event.metaKey &&
|
|
16
|
-
!event.ctrlKey &&
|
|
17
|
-
!event.shiftKey &&
|
|
18
|
-
event.button == 0
|
|
19
|
-
) {
|
|
5
|
+
function handleClick(event: MouseEvent, to: string, templateParams?: TemplateParams) {
|
|
6
|
+
if (!event.metaKey && !event.ctrlKey && !event.shiftKey && event.button == 0) {
|
|
20
7
|
event.preventDefault();
|
|
21
8
|
navigate({ to, templateParams });
|
|
22
9
|
}
|
|
@@ -25,8 +12,7 @@ function handleClick(
|
|
|
25
12
|
/**
|
|
26
13
|
* @noInheritDoc
|
|
27
14
|
*/
|
|
28
|
-
export interface ConfigurableLinkProps
|
|
29
|
-
extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
15
|
+
export interface ConfigurableLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
30
16
|
to: string;
|
|
31
17
|
templateParams?: TemplateParams;
|
|
32
18
|
}
|
package/src/Extension.tsx
CHANGED
|
@@ -1,27 +1,15 @@
|
|
|
1
|
-
import { renderExtension } from
|
|
2
|
-
import React, {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
type ReactElement,
|
|
9
|
-
} from "react";
|
|
10
|
-
import type { Parcel } from "single-spa";
|
|
11
|
-
import { ComponentContext } from ".";
|
|
12
|
-
import type { ExtensionData } from "./ComponentContext";
|
|
1
|
+
import { renderExtension } from '@openmrs/esm-extensions';
|
|
2
|
+
import React, { useCallback, useContext, useEffect, useRef, useState, type ReactElement } from 'react';
|
|
3
|
+
import type { Parcel } from 'single-spa';
|
|
4
|
+
import { ComponentContext } from '.';
|
|
5
|
+
import type { ExtensionData } from './ComponentContext';
|
|
13
6
|
|
|
14
7
|
export type ExtensionProps = {
|
|
15
8
|
state?: Record<string, any>;
|
|
16
9
|
/** @deprecated Pass a function as the child of `ExtensionSlot` instead. */
|
|
17
|
-
wrap?(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
): ReactElement<any, any> | null;
|
|
21
|
-
} & Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
22
|
-
children?:
|
|
23
|
-
| React.ReactNode
|
|
24
|
-
| ((slot: React.ReactNode, extension?: ExtensionData) => React.ReactNode);
|
|
10
|
+
wrap?(slot: React.ReactNode, extension: ExtensionData): ReactElement<any, any> | null;
|
|
11
|
+
} & Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
12
|
+
children?: React.ReactNode | ((slot: React.ReactNode, extension?: ExtensionData) => React.ReactNode);
|
|
25
13
|
};
|
|
26
14
|
|
|
27
15
|
/**
|
|
@@ -33,12 +21,7 @@ export type ExtensionProps = {
|
|
|
33
21
|
* Usage of this component *must* have an ancestor `<ExtensionSlot>`,
|
|
34
22
|
* and *must* only be used once within that `<ExtensionSlot>`.
|
|
35
23
|
*/
|
|
36
|
-
export const Extension: React.FC<ExtensionProps> = ({
|
|
37
|
-
state,
|
|
38
|
-
children,
|
|
39
|
-
wrap,
|
|
40
|
-
...divProps
|
|
41
|
-
}) => {
|
|
24
|
+
export const Extension: React.FC<ExtensionProps> = ({ state, children, wrap, ...divProps }) => {
|
|
42
25
|
const [domElement, setDomElement] = useState<HTMLDivElement>();
|
|
43
26
|
const { extension } = useContext(ComponentContext);
|
|
44
27
|
const parcel = useRef<Parcel | null>(null);
|
|
@@ -49,10 +32,8 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
49
32
|
if (wrap) {
|
|
50
33
|
console.warn(
|
|
51
34
|
`'wrap' prop of Extension is being used ${
|
|
52
|
-
extension?.extensionId
|
|
53
|
-
|
|
54
|
-
: ""
|
|
55
|
-
}. This will be removed in a future release.`
|
|
35
|
+
extension?.extensionId ? `by ${extension.extensionId} in ${extension.extensionSlotName}` : ''
|
|
36
|
+
}. This will be removed in a future release.`,
|
|
56
37
|
);
|
|
57
38
|
}
|
|
58
39
|
// we only warn when component mounts
|
|
@@ -63,7 +44,7 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
63
44
|
(node: HTMLDivElement) => {
|
|
64
45
|
setDomElement(node);
|
|
65
46
|
},
|
|
66
|
-
[setDomElement]
|
|
47
|
+
[setDomElement],
|
|
67
48
|
);
|
|
68
49
|
|
|
69
50
|
useEffect(() => {
|
|
@@ -82,7 +63,7 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
82
63
|
extension.extensionSlotModuleName,
|
|
83
64
|
extension.extensionId,
|
|
84
65
|
undefined,
|
|
85
|
-
state
|
|
66
|
+
state,
|
|
86
67
|
).then((newParcel) => {
|
|
87
68
|
parcel.current = newParcel;
|
|
88
69
|
rendering.current = false;
|
|
@@ -92,20 +73,20 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
92
73
|
if (parcel && parcel.current) {
|
|
93
74
|
const status = parcel.current.getStatus();
|
|
94
75
|
switch (status) {
|
|
95
|
-
case
|
|
76
|
+
case 'MOUNTING':
|
|
96
77
|
parcel.current.mountPromise.then(() => {
|
|
97
|
-
if (parcel.current?.getStatus() ===
|
|
78
|
+
if (parcel.current?.getStatus() === 'MOUNTED') {
|
|
98
79
|
parcel.current.unmount();
|
|
99
80
|
}
|
|
100
81
|
});
|
|
101
82
|
break;
|
|
102
|
-
case
|
|
83
|
+
case 'MOUNTED':
|
|
103
84
|
parcel.current.unmount();
|
|
104
85
|
break;
|
|
105
|
-
case
|
|
86
|
+
case 'UPDATING':
|
|
106
87
|
if (updatePromise.current) {
|
|
107
88
|
updatePromise.current.then(() => {
|
|
108
|
-
if (parcel.current?.getStatus() ===
|
|
89
|
+
if (parcel.current?.getStatus() === 'MOUNTED') {
|
|
109
90
|
parcel.current.unmount();
|
|
110
91
|
}
|
|
111
92
|
});
|
|
@@ -118,41 +99,25 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
118
99
|
// we intentionally do not re-run this hook if state gets updated
|
|
119
100
|
// state updates are handled in the next useEffect hook
|
|
120
101
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
-
}, [
|
|
122
|
-
extension?.extensionSlotName,
|
|
123
|
-
extension?.extensionId,
|
|
124
|
-
extension?.extensionSlotModuleName,
|
|
125
|
-
domElement,
|
|
126
|
-
]);
|
|
102
|
+
}, [extension?.extensionSlotName, extension?.extensionId, extension?.extensionSlotModuleName, domElement]);
|
|
127
103
|
|
|
128
104
|
useEffect(() => {
|
|
129
|
-
if (
|
|
130
|
-
parcel.current
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// if we were trying to update but the component was unmounted
|
|
144
|
-
// while this was happening, ignore the error
|
|
145
|
-
if (
|
|
146
|
-
!(err instanceof Error) ||
|
|
147
|
-
!err.message.includes("minified message #32") ||
|
|
148
|
-
parcel.current?.getStatus() === "MOUNTED"
|
|
149
|
-
) {
|
|
150
|
-
throw err;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
105
|
+
if (parcel.current && parcel.current.update && parcel.current.getStatus() !== 'UNMOUNTING') {
|
|
106
|
+
Promise.all([parcel.current.mountPromise, updatePromise.current]).then(() => {
|
|
107
|
+
if (parcel?.current?.getStatus() === 'MOUNTED' && parcel.current.update) {
|
|
108
|
+
updatePromise.current = parcel.current.update({ ...state }).catch((err) => {
|
|
109
|
+
// if we were trying to update but the component was unmounted
|
|
110
|
+
// while this was happening, ignore the error
|
|
111
|
+
if (
|
|
112
|
+
!(err instanceof Error) ||
|
|
113
|
+
!err.message.includes('minified message #32') ||
|
|
114
|
+
parcel.current?.getStatus() === 'MOUNTED'
|
|
115
|
+
) {
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
154
119
|
}
|
|
155
|
-
);
|
|
120
|
+
});
|
|
156
121
|
}
|
|
157
122
|
}, [state]);
|
|
158
123
|
|
|
@@ -160,15 +125,10 @@ export const Extension: React.FC<ExtensionProps> = ({
|
|
|
160
125
|
// positioning in order to allow the UI Editor to absolutely position
|
|
161
126
|
// elements within it.
|
|
162
127
|
const slot = (
|
|
163
|
-
<div
|
|
164
|
-
ref={ref}
|
|
165
|
-
data-extension-id={extension?.extensionId}
|
|
166
|
-
style={{ position: "relative" }}
|
|
167
|
-
{...divProps}
|
|
168
|
-
/>
|
|
128
|
+
<div ref={ref} data-extension-id={extension?.extensionId} style={{ position: 'relative' }} {...divProps} />
|
|
169
129
|
);
|
|
170
130
|
|
|
171
|
-
if (typeof children ===
|
|
131
|
+
if (typeof children === 'function' && !React.isValidElement(children)) {
|
|
172
132
|
return <>{children(slot, extension)}</>;
|
|
173
133
|
}
|
|
174
134
|
|
package/src/ExtensionSlot.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React, { useRef, useMemo } from
|
|
2
|
-
import type { ConnectedExtension } from
|
|
3
|
-
import { ComponentContext } from
|
|
4
|
-
import { Extension } from
|
|
5
|
-
import { useExtensionSlot } from
|
|
1
|
+
import React, { useRef, useMemo } from 'react';
|
|
2
|
+
import type { ConnectedExtension } from '@openmrs/esm-extensions';
|
|
3
|
+
import { ComponentContext } from './ComponentContext';
|
|
4
|
+
import { Extension } from './Extension';
|
|
5
|
+
import { useExtensionSlot } from './useExtensionSlot';
|
|
6
6
|
|
|
7
7
|
export interface ExtensionSlotBaseProps {
|
|
8
8
|
name: string;
|
|
@@ -20,14 +20,9 @@ export interface OldExtensionSlotBaseProps {
|
|
|
20
20
|
state?: Record<string, any>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export type ExtensionSlotProps = (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) &
|
|
27
|
-
Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
28
|
-
children?:
|
|
29
|
-
| React.ReactNode
|
|
30
|
-
| ((extension: ConnectedExtension) => React.ReactNode);
|
|
23
|
+
export type ExtensionSlotProps = (OldExtensionSlotBaseProps | ExtensionSlotBaseProps) &
|
|
24
|
+
Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
25
|
+
children?: React.ReactNode | ((extension: ConnectedExtension) => React.ReactNode);
|
|
31
26
|
};
|
|
32
27
|
|
|
33
28
|
function defaultSelect(extensions: Array<ConnectedExtension>) {
|
|
@@ -93,7 +88,7 @@ export function ExtensionSlot({
|
|
|
93
88
|
}: ExtensionSlotProps) {
|
|
94
89
|
if (children && state) {
|
|
95
90
|
throw new Error(
|
|
96
|
-
|
|
91
|
+
'Both children and state have been provided. If children are provided, the state must be passed as a prop to the `Extension` component.',
|
|
97
92
|
);
|
|
98
93
|
}
|
|
99
94
|
|
|
@@ -101,13 +96,10 @@ export function ExtensionSlot({
|
|
|
101
96
|
const slotRef = useRef(null);
|
|
102
97
|
const { extensions, extensionSlotModuleName } = useExtensionSlot(name);
|
|
103
98
|
|
|
104
|
-
const extensionsToRender = useMemo(
|
|
105
|
-
() => select(extensions),
|
|
106
|
-
[select, extensions]
|
|
107
|
-
);
|
|
99
|
+
const extensionsToRender = useMemo(() => select(extensions), [select, extensions]);
|
|
108
100
|
|
|
109
101
|
const extensionsFromChildrenFunction = useMemo(() => {
|
|
110
|
-
if (typeof children ==
|
|
102
|
+
if (typeof children == 'function' && !React.isValidElement(children)) {
|
|
111
103
|
return extensionsToRender.map((extension) => children(extension));
|
|
112
104
|
}
|
|
113
105
|
}, [children, extensionsToRender]);
|
|
@@ -117,7 +109,7 @@ export function ExtensionSlot({
|
|
|
117
109
|
ref={slotRef}
|
|
118
110
|
data-extension-slot-name={name}
|
|
119
111
|
data-extension-slot-module-name={extensionSlotModuleName}
|
|
120
|
-
style={{ ...style, position:
|
|
112
|
+
style={{ ...style, position: 'relative' }}
|
|
121
113
|
{...divProps}
|
|
122
114
|
>
|
|
123
115
|
{name &&
|
|
@@ -133,10 +125,9 @@ export function ExtensionSlot({
|
|
|
133
125
|
},
|
|
134
126
|
}}
|
|
135
127
|
>
|
|
136
|
-
{extensionsFromChildrenFunction?.[i] ??
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)}
|
|
128
|
+
{extensionsFromChildrenFunction?.[i] ?? (typeof children != 'function' ? children : null) ?? (
|
|
129
|
+
<Extension state={state} />
|
|
130
|
+
)}
|
|
140
131
|
</ComponentContext.Provider>
|
|
141
132
|
))}
|
|
142
133
|
</div>
|
package/src/UserHasAccess.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
-
import { getCurrentUser, LoggedInUser, userHasAccess } from
|
|
3
|
-
import React, { useEffect, useState } from
|
|
2
|
+
import { getCurrentUser, LoggedInUser, userHasAccess } from '@openmrs/esm-api';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
export interface UserHasAccessProps {
|
|
6
6
|
privilege: string | string[];
|
|
@@ -8,11 +8,7 @@ export interface UserHasAccessProps {
|
|
|
8
8
|
children?: React.ReactNode;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const UserHasAccess: React.FC<UserHasAccessProps> = ({
|
|
12
|
-
privilege,
|
|
13
|
-
fallback,
|
|
14
|
-
children,
|
|
15
|
-
}) => {
|
|
11
|
+
export const UserHasAccess: React.FC<UserHasAccessProps> = ({ privilege, fallback, children }) => {
|
|
16
12
|
const [user, setUser] = useState<LoggedInUser | null>(null);
|
|
17
13
|
|
|
18
14
|
useEffect(() => {
|