@openmrs/esm-react-utils 5.8.2-pre.2389 → 5.8.2-pre.2393
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 +5 -5
- package/dist/openmrs-esm-react-utils.js +1 -1
- package/dist/openmrs-esm-react-utils.js.map +1 -1
- package/jest.config.js +1 -0
- package/package.json +10 -10
- package/src/Extension.tsx +11 -31
- package/src/ExtensionSlot.tsx +10 -10
- package/src/extensions.test.tsx +13 -52
- package/src/index.ts +1 -0
- package/src/public.ts +1 -0
- package/src/useAssignedExtensionIds.ts +1 -1
- package/src/useAssignedExtensions.ts +3 -10
- package/src/useConnectedExtensions.ts +3 -24
- package/src/useExtensionSlot.ts +2 -2
- package/src/useExtensionSlotMeta.ts +2 -2
- package/src/useExtensionSlotStore.ts +6 -0
- package/src/useExtensionStore.ts +1 -2
- package/src/useStore.ts +7 -4
package/jest.config.js
CHANGED
|
@@ -4,6 +4,7 @@ module.exports = {
|
|
|
4
4
|
},
|
|
5
5
|
setupFilesAfterEnv: ['<rootDir>/src/setup-tests.js'],
|
|
6
6
|
moduleNameMapper: {
|
|
7
|
+
'^lodash-es$': 'lodash',
|
|
7
8
|
'^lodash-es/(.*)$': 'lodash/$1',
|
|
8
9
|
'@openmrs/esm-error-handling': '<rootDir>/__mocks__/openmrs-esm-error-handling.mock.ts',
|
|
9
10
|
'@openmrs/esm-state': '@openmrs/esm-state/mock',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-react-utils",
|
|
3
|
-
"version": "5.8.2-pre.
|
|
3
|
+
"version": "5.8.2-pre.2393",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "React utilities for OpenMRS.",
|
|
6
6
|
"browser": "dist/openmrs-esm-react-utils.js",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"swr": "2.x"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@openmrs/esm-api": "5.8.2-pre.
|
|
65
|
-
"@openmrs/esm-config": "5.8.2-pre.
|
|
66
|
-
"@openmrs/esm-context": "5.8.2-pre.
|
|
67
|
-
"@openmrs/esm-error-handling": "5.8.2-pre.
|
|
68
|
-
"@openmrs/esm-extensions": "5.8.2-pre.
|
|
69
|
-
"@openmrs/esm-feature-flags": "5.8.2-pre.
|
|
70
|
-
"@openmrs/esm-globals": "5.8.2-pre.
|
|
71
|
-
"@openmrs/esm-navigation": "5.8.2-pre.
|
|
72
|
-
"@openmrs/esm-utils": "5.8.2-pre.
|
|
64
|
+
"@openmrs/esm-api": "5.8.2-pre.2393",
|
|
65
|
+
"@openmrs/esm-config": "5.8.2-pre.2393",
|
|
66
|
+
"@openmrs/esm-context": "5.8.2-pre.2393",
|
|
67
|
+
"@openmrs/esm-error-handling": "5.8.2-pre.2393",
|
|
68
|
+
"@openmrs/esm-extensions": "5.8.2-pre.2393",
|
|
69
|
+
"@openmrs/esm-feature-flags": "5.8.2-pre.2393",
|
|
70
|
+
"@openmrs/esm-globals": "5.8.2-pre.2393",
|
|
71
|
+
"@openmrs/esm-navigation": "5.8.2-pre.2393",
|
|
72
|
+
"@openmrs/esm-utils": "5.8.2-pre.2393",
|
|
73
73
|
"dayjs": "^1.10.8",
|
|
74
74
|
"i18next": "^21.10.0",
|
|
75
75
|
"react": "^18.1.0",
|
package/src/Extension.tsx
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
2
|
import { renderExtension } from '@openmrs/esm-extensions';
|
|
3
|
-
import React, { useCallback, useContext, useEffect, useRef, useState
|
|
4
|
-
import type
|
|
3
|
+
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { type Parcel } from 'single-spa';
|
|
5
5
|
import { ComponentContext } from '.';
|
|
6
|
-
import type { ExtensionData } from './ComponentContext';
|
|
7
6
|
|
|
8
|
-
export type ExtensionProps = {
|
|
9
|
-
state?: Record<string,
|
|
10
|
-
|
|
11
|
-
wrap?(slot: React.ReactNode, extension: ExtensionData): ReactElement<any, any> | null;
|
|
12
|
-
} & Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
13
|
-
children?: React.ReactNode | ((slot: React.ReactNode, extension?: ExtensionData) => React.ReactNode);
|
|
14
|
-
};
|
|
7
|
+
export type ExtensionProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
8
|
+
state?: Record<string, unknown>;
|
|
9
|
+
};
|
|
15
10
|
|
|
16
11
|
/**
|
|
17
12
|
* Represents the position in the DOM where each extension within
|
|
@@ -22,24 +17,13 @@ export type ExtensionProps = {
|
|
|
22
17
|
* Usage of this component *must* have an ancestor `<ExtensionSlot>`,
|
|
23
18
|
* and *must* only be used once within that `<ExtensionSlot>`.
|
|
24
19
|
*/
|
|
25
|
-
export const Extension: React.FC<ExtensionProps> = ({ state, children,
|
|
20
|
+
export const Extension: React.FC<ExtensionProps> = ({ state, children, ...divProps }) => {
|
|
26
21
|
const [domElement, setDomElement] = useState<HTMLDivElement>();
|
|
27
22
|
const { extension } = useContext(ComponentContext);
|
|
28
23
|
const parcel = useRef<Parcel | null>(null);
|
|
29
24
|
const updatePromise = useRef<Promise<void>>(Promise.resolve());
|
|
30
25
|
const rendering = useRef<boolean>(false);
|
|
31
26
|
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (wrap) {
|
|
34
|
-
console.warn(
|
|
35
|
-
`'wrap' prop of Extension is being used ${
|
|
36
|
-
extension?.extensionId ? `by ${extension.extensionId} in ${extension.extensionSlotName}` : ''
|
|
37
|
-
}. This will be removed in a future release.`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
// we only warn when component mounts
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
27
|
const ref = useCallback(
|
|
44
28
|
(node: HTMLDivElement) => {
|
|
45
29
|
setDomElement(node);
|
|
@@ -123,13 +107,9 @@ export const Extension: React.FC<ExtensionProps> = ({ state, children, wrap, ...
|
|
|
123
107
|
// The extension is rendered into the `<div>`. The `<div>` has relative
|
|
124
108
|
// positioning in order to allow the UI Editor to absolutely position
|
|
125
109
|
// elements within it.
|
|
126
|
-
|
|
127
|
-
<div ref={ref} data-extension-id={extension?.extensionId} style={{ position: 'relative' }} {...divProps}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return <>{children(slot, extension)}</>;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return extension && wrap ? wrap(slot, extension) : slot;
|
|
110
|
+
return extension ? (
|
|
111
|
+
<div ref={ref} data-extension-id={extension?.extensionId} style={{ position: 'relative' }} {...divProps}>
|
|
112
|
+
{children}
|
|
113
|
+
</div>
|
|
114
|
+
) : null;
|
|
135
115
|
};
|
package/src/ExtensionSlot.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
2
|
import React, { useRef, useMemo } from 'react';
|
|
3
|
-
import type
|
|
3
|
+
import { type AssignedExtension } from '@openmrs/esm-extensions';
|
|
4
4
|
import { ComponentContext } from './ComponentContext';
|
|
5
5
|
import { Extension } from './Extension';
|
|
6
6
|
import { useExtensionSlot } from './useExtensionSlot';
|
|
@@ -9,24 +9,24 @@ export interface ExtensionSlotBaseProps {
|
|
|
9
9
|
name: string;
|
|
10
10
|
/** @deprecated Use `name` */
|
|
11
11
|
extensionSlotName?: string;
|
|
12
|
-
select?: (extensions: Array<
|
|
13
|
-
state?: Record<string,
|
|
12
|
+
select?: (extensions: Array<AssignedExtension>) => Array<AssignedExtension>;
|
|
13
|
+
state?: Record<string, unknown>;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface OldExtensionSlotBaseProps {
|
|
17
17
|
name?: string;
|
|
18
18
|
/** @deprecated Use `name` */
|
|
19
19
|
extensionSlotName: string;
|
|
20
|
-
select?: (extensions: Array<
|
|
21
|
-
state?: Record<string,
|
|
20
|
+
select?: (extensions: Array<AssignedExtension>) => Array<AssignedExtension>;
|
|
21
|
+
state?: Record<string, unknown>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export type ExtensionSlotProps = (OldExtensionSlotBaseProps | ExtensionSlotBaseProps) &
|
|
25
25
|
Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
26
|
-
children?: React.ReactNode | ((extension:
|
|
26
|
+
children?: React.ReactNode | ((extension: AssignedExtension, state?: Record<string, unknown>) => React.ReactNode);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
function defaultSelect(extensions: Array<
|
|
29
|
+
function defaultSelect(extensions: Array<AssignedExtension>) {
|
|
30
30
|
return extensions;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -101,7 +101,7 @@ export function ExtensionSlot({
|
|
|
101
101
|
|
|
102
102
|
const extensionsFromChildrenFunction = useMemo(() => {
|
|
103
103
|
if (typeof children == 'function' && !React.isValidElement(children)) {
|
|
104
|
-
return extensionsToRender.map((extension) => children(extension));
|
|
104
|
+
return extensionsToRender.map((extension) => children(extension, state));
|
|
105
105
|
}
|
|
106
106
|
}, [children, extensionsToRender]);
|
|
107
107
|
|
|
@@ -114,7 +114,7 @@ export function ExtensionSlot({
|
|
|
114
114
|
{...divProps}
|
|
115
115
|
>
|
|
116
116
|
{name &&
|
|
117
|
-
extensionsToRender
|
|
117
|
+
extensionsToRender?.map((extension, i) => (
|
|
118
118
|
<ComponentContext.Provider
|
|
119
119
|
key={extension.id}
|
|
120
120
|
value={{
|
|
@@ -127,7 +127,7 @@ export function ExtensionSlot({
|
|
|
127
127
|
},
|
|
128
128
|
}}
|
|
129
129
|
>
|
|
130
|
-
{extensionsFromChildrenFunction?.[i] ?? (typeof children
|
|
130
|
+
{extensionsFromChildrenFunction?.[i] ?? (typeof children !== 'function' ? children : null) ?? (
|
|
131
131
|
<Extension state={state} />
|
|
132
132
|
)}
|
|
133
133
|
</ComponentContext.Provider>
|
package/src/extensions.test.tsx
CHANGED
|
@@ -122,21 +122,15 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
122
122
|
disableTranslations: true,
|
|
123
123
|
})(() => {
|
|
124
124
|
const metas = useExtensionSlotMeta('Box');
|
|
125
|
-
const wrapItem = useCallback(
|
|
126
|
-
(slot: React.ReactNode, extension?: ExtensionData) => {
|
|
127
|
-
return (
|
|
128
|
-
<div>
|
|
129
|
-
<h1>{metas[getExtensionNameFromId(extension?.extensionId ?? '')].code}</h1>
|
|
130
|
-
{slot}
|
|
131
|
-
</div>
|
|
132
|
-
);
|
|
133
|
-
},
|
|
134
|
-
[metas],
|
|
135
|
-
);
|
|
136
125
|
return (
|
|
137
126
|
<div>
|
|
138
127
|
<ExtensionSlot name="Box">
|
|
139
|
-
|
|
128
|
+
{(extension) => (
|
|
129
|
+
<div>
|
|
130
|
+
<h1>{metas[getExtensionNameFromId(extension?.id ?? '')].code}</h1>
|
|
131
|
+
<Extension />
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
140
134
|
</ExtensionSlot>
|
|
141
135
|
</div>
|
|
142
136
|
);
|
|
@@ -163,21 +157,15 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
163
157
|
})(() => {
|
|
164
158
|
const [suffix, toggleSuffix] = useReducer((suffix) => (suffix == '!' ? '?' : '!'), '!');
|
|
165
159
|
const metas = useExtensionSlotMeta('Box');
|
|
166
|
-
const wrapItem = useCallback(
|
|
167
|
-
(slot: React.ReactNode, extension?: ExtensionData) => {
|
|
168
|
-
return (
|
|
169
|
-
<div>
|
|
170
|
-
<h1>{metas[getExtensionNameFromId(extension?.extensionId ?? '')].code}</h1>
|
|
171
|
-
{slot}
|
|
172
|
-
</div>
|
|
173
|
-
);
|
|
174
|
-
},
|
|
175
|
-
[metas],
|
|
176
|
-
);
|
|
177
160
|
return (
|
|
178
161
|
<div>
|
|
179
162
|
<ExtensionSlot name="Box">
|
|
180
|
-
|
|
163
|
+
{(extension) => (
|
|
164
|
+
<div>
|
|
165
|
+
<h1>{metas[getExtensionNameFromId(extension?.id ?? '')].code}</h1>
|
|
166
|
+
<Extension state={{ suffix }} />
|
|
167
|
+
</div>
|
|
168
|
+
)}
|
|
181
169
|
</ExtensionSlot>
|
|
182
170
|
<button onClick={toggleSuffix}>Toggle suffix</button>
|
|
183
171
|
</div>
|
|
@@ -209,7 +197,7 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
209
197
|
return (
|
|
210
198
|
<div>
|
|
211
199
|
<ExtensionSlot name="Box">
|
|
212
|
-
{(extension
|
|
200
|
+
{(extension) => (
|
|
213
201
|
<div data-testid={extension.name}>
|
|
214
202
|
<h2>{extension.meta.code}</h2>
|
|
215
203
|
<Extension />
|
|
@@ -226,33 +214,6 @@ describe('ExtensionSlot, Extension, and useExtensionSlotMeta', () => {
|
|
|
226
214
|
expect(within(screen.getByTestId('Hindi')).getByRole('heading')).toHaveTextContent('hi');
|
|
227
215
|
});
|
|
228
216
|
|
|
229
|
-
test('Extension renders with child function', async () => {
|
|
230
|
-
registerSimpleExtension('Hindi', 'esm-languages-app', undefined, {
|
|
231
|
-
code: 'hi',
|
|
232
|
-
});
|
|
233
|
-
attach('Box', 'Hindi');
|
|
234
|
-
const App = openmrsComponentDecorator({
|
|
235
|
-
moduleName: 'esm-languages-app',
|
|
236
|
-
featureName: 'Languages',
|
|
237
|
-
disableTranslations: true,
|
|
238
|
-
})(() => {
|
|
239
|
-
return (
|
|
240
|
-
<div>
|
|
241
|
-
<ExtensionSlot name="Box">
|
|
242
|
-
{() => <Extension>{(slot) => <div data-testid="custom-wrapper">{slot}</div>}</Extension>}
|
|
243
|
-
</ExtensionSlot>
|
|
244
|
-
</div>
|
|
245
|
-
);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
render(<App />);
|
|
249
|
-
|
|
250
|
-
await waitFor(() => expect(screen.getByTestId('custom-wrapper')).toBeInTheDocument());
|
|
251
|
-
|
|
252
|
-
// essentially: is the first child of custom-wrapper the extension?
|
|
253
|
-
expect(screen.getByTestId('custom-wrapper').children[0]).toHaveAttribute('data-extension-id', 'Hindi');
|
|
254
|
-
});
|
|
255
|
-
|
|
256
217
|
test('Extensions behind feature flags only render when their feature flag is enabled', async () => {
|
|
257
218
|
registerSimpleExtension('Arabic', 'esm-languages-app');
|
|
258
219
|
registerSimpleExtension('Turkish', 'esm-languages-app', undefined, undefined, 'turkic');
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from './useDefineAppContext';
|
|
|
20
20
|
export * from './useExtensionInternalStore';
|
|
21
21
|
export * from './useExtensionSlot';
|
|
22
22
|
export * from './useExtensionSlotMeta';
|
|
23
|
+
export * from './useExtensionSlotStore';
|
|
23
24
|
export * from './useExtensionStore';
|
|
24
25
|
export * from './useFeatureFlag';
|
|
25
26
|
export * from './useForceUpdate';
|
package/src/public.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './useDebounce';
|
|
|
18
18
|
export * from './useDefineAppContext';
|
|
19
19
|
export * from './useExtensionSlotMeta';
|
|
20
20
|
export * from './useExtensionStore';
|
|
21
|
+
export * from './useExtensionSlotStore';
|
|
21
22
|
export * from './useFeatureFlag';
|
|
22
23
|
export * from './useLayoutType';
|
|
23
24
|
export * from './useLocations';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { getExtensionStore } from '@openmrs/esm-extensions';
|
|
4
|
-
import isEqual from 'lodash-es
|
|
4
|
+
import { isEqual } from 'lodash-es';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Gets the assigned extension ids for a given extension slot name.
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import {
|
|
3
|
-
import { useExtensionStore } from './useExtensionStore';
|
|
2
|
+
import { useExtensionSlotStore } from './useExtensionSlotStore';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Gets the assigned extensions for a given extension slot name.
|
|
7
|
-
* Does not consider if offline or online.
|
|
8
6
|
* @param slotName The name of the slot to get the assigned extensions for.
|
|
9
7
|
*/
|
|
10
8
|
export function useAssignedExtensions(slotName: string) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const extensions = useMemo(() => {
|
|
14
|
-
return slots[slotName]?.assignedExtensions ?? [];
|
|
15
|
-
}, [slots, slotName]);
|
|
16
|
-
|
|
17
|
-
return extensions;
|
|
9
|
+
const slotStore = useExtensionSlotStore(slotName);
|
|
10
|
+
return slotStore?.assignedExtensions;
|
|
18
11
|
}
|
|
@@ -1,31 +1,10 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import {
|
|
3
|
-
import type { ConnectedExtension } from '@openmrs/esm-extensions';
|
|
4
|
-
import { getConnectedExtensions } from '@openmrs/esm-extensions';
|
|
5
|
-
import { useConnectivity } from './useConnectivity';
|
|
2
|
+
import { type ConnectedExtension } from '@openmrs/esm-extensions';
|
|
6
3
|
import { useAssignedExtensions } from './useAssignedExtensions';
|
|
7
|
-
import { useStore } from './useStore';
|
|
8
|
-
import { featureFlagsStore } from '@openmrs/esm-feature-flags';
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
6
|
* Gets the assigned extension for a given extension slot name.
|
|
12
|
-
* Considers if offline or online, and what feature flags are enabled.
|
|
13
7
|
* @param slotName The name of the slot to get the assigned extensions for.
|
|
8
|
+
* @deprecated Use useAssignedExtensions instead
|
|
14
9
|
*/
|
|
15
|
-
export
|
|
16
|
-
const online = useConnectivity();
|
|
17
|
-
const assignedExtensions = useAssignedExtensions(slotName);
|
|
18
|
-
const featureFlagStore = useStore(featureFlagsStore);
|
|
19
|
-
|
|
20
|
-
const enabledFeatureFlags = useMemo(() => {
|
|
21
|
-
return Object.entries(featureFlagStore.flags)
|
|
22
|
-
.filter(([, { enabled }]) => enabled)
|
|
23
|
-
.map(([name]) => name);
|
|
24
|
-
}, [featureFlagStore.flags]);
|
|
25
|
-
|
|
26
|
-
const connectedExtensions = useMemo(() => {
|
|
27
|
-
return getConnectedExtensions(assignedExtensions, online, enabledFeatureFlags);
|
|
28
|
-
}, [assignedExtensions, online, enabledFeatureFlags]);
|
|
29
|
-
|
|
30
|
-
return connectedExtensions;
|
|
31
|
-
}
|
|
10
|
+
export const useConnectedExtensions = useAssignedExtensions as (slotName: string) => Array<ConnectedExtension>;
|
package/src/useExtensionSlot.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useContext, useEffect } from 'react';
|
|
2
2
|
import { registerExtensionSlot } from '@openmrs/esm-extensions';
|
|
3
3
|
import { ComponentContext } from './ComponentContext';
|
|
4
|
-
import {
|
|
4
|
+
import { useAssignedExtensions } from './useAssignedExtensions';
|
|
5
5
|
|
|
6
6
|
/** @internal */
|
|
7
7
|
export function useExtensionSlot(slotName: string) {
|
|
@@ -15,7 +15,7 @@ export function useExtensionSlot(slotName: string) {
|
|
|
15
15
|
registerExtensionSlot(moduleName, slotName);
|
|
16
16
|
}, []);
|
|
17
17
|
|
|
18
|
-
const extensions =
|
|
18
|
+
const extensions = useAssignedExtensions(slotName);
|
|
19
19
|
|
|
20
20
|
return {
|
|
21
21
|
extensions,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
2
|
import type { ExtensionMeta } from '@openmrs/esm-extensions';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { useAssignedExtensions } from './useAssignedExtensions';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Extract meta data from all extension for a given extension slot.
|
|
8
8
|
* @param extensionSlotName
|
|
9
9
|
*/
|
|
10
10
|
export function useExtensionSlotMeta<T = ExtensionMeta>(extensionSlotName: string) {
|
|
11
|
-
const extensions =
|
|
11
|
+
const extensions = useAssignedExtensions(extensionSlotName);
|
|
12
12
|
|
|
13
13
|
return useMemo(() => Object.fromEntries(extensions.map((ext) => [ext.name, ext.meta as T])), [extensions]);
|
|
14
14
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** @module @category Extension */
|
|
2
|
+
import { type ExtensionSlotState, type ExtensionStore, getExtensionStore } from '@openmrs/esm-extensions';
|
|
3
|
+
import { useStore } from './useStore';
|
|
4
|
+
|
|
5
|
+
export const useExtensionSlotStore = (slot: string) =>
|
|
6
|
+
useStore<ExtensionStore, ExtensionSlotState>(getExtensionStore(), (state) => state.slots?.[slot]);
|
package/src/useExtensionStore.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import type
|
|
3
|
-
import { getExtensionStore } from '@openmrs/esm-extensions';
|
|
2
|
+
import { type ExtensionStore, getExtensionStore } from '@openmrs/esm-extensions';
|
|
4
3
|
import { createUseStore } from './useStore';
|
|
5
4
|
|
|
6
5
|
export const useExtensionStore = createUseStore<ExtensionStore>(getExtensionStore());
|
package/src/useStore.ts
CHANGED
|
@@ -17,7 +17,7 @@ function bindActions<T>(store: StoreApi<T>, actions: Actions<T>): BoundActions {
|
|
|
17
17
|
const bound = {};
|
|
18
18
|
|
|
19
19
|
for (let i in actions) {
|
|
20
|
-
bound[i] = function (...args) {
|
|
20
|
+
bound[i] = function (...args: Array<unknown>) {
|
|
21
21
|
store.setState((state) => {
|
|
22
22
|
let _args = [state, ...args];
|
|
23
23
|
return actions[i](..._args);
|
|
@@ -28,13 +28,16 @@ function bindActions<T>(store: StoreApi<T>, actions: Actions<T>): BoundActions {
|
|
|
28
28
|
return bound;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const defaultSelectFunction =
|
|
31
|
+
const defaultSelectFunction =
|
|
32
|
+
<T, U>() =>
|
|
33
|
+
(x: T) =>
|
|
34
|
+
x as unknown as U;
|
|
32
35
|
|
|
33
36
|
function useStore<T, U>(store: StoreApi<T>): T;
|
|
34
37
|
function useStore<T, U>(store: StoreApi<T>, select: (state: T) => U): U;
|
|
35
38
|
function useStore<T, U>(store: StoreApi<T>, select: undefined, actions: Actions<T>): T & BoundActions;
|
|
36
39
|
function useStore<T, U>(store: StoreApi<T>, select: (state: T) => U, actions: Actions<T>): U & BoundActions;
|
|
37
|
-
function useStore<T, U>(store: StoreApi<T>, select: (state: T) => U = defaultSelectFunction, actions?: Actions<T>) {
|
|
40
|
+
function useStore<T, U>(store: StoreApi<T>, select: (state: T) => U = defaultSelectFunction(), actions?: Actions<T>) {
|
|
38
41
|
const [state, setState] = useState<U>(() => select(store.getState()));
|
|
39
42
|
useEffect(() => subscribeTo(store, select, setState), [store, select]);
|
|
40
43
|
|
|
@@ -50,7 +53,7 @@ function useStore<T, U>(store: StoreApi<T>, select: (state: T) => U = defaultSel
|
|
|
50
53
|
* @returns
|
|
51
54
|
*/
|
|
52
55
|
function useStoreWithActions<T>(store: StoreApi<T>, actions: Actions<T>): T & BoundActions {
|
|
53
|
-
return useStore(store, defaultSelectFunction, actions);
|
|
56
|
+
return useStore(store, defaultSelectFunction<T, T>(), actions);
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
/**
|